qemu/target/s390x/mem_helper.c
<<
>>
Prefs
   1/*
   2 *  S/390 memory access helper routines
   3 *
   4 *  Copyright (c) 2009 Ulrich Hecht
   5 *  Copyright (c) 2009 Alexander Graf
   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.1 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
  21#include "qemu/osdep.h"
  22#include "cpu.h"
  23#include "internal.h"
  24#include "exec/helper-proto.h"
  25#include "exec/exec-all.h"
  26#include "exec/cpu_ldst.h"
  27#include "qemu/int128.h"
  28#include "qemu/atomic128.h"
  29
  30#if !defined(CONFIG_USER_ONLY)
  31#include "hw/s390x/storage-keys.h"
  32#endif
  33
  34/*****************************************************************************/
  35/* Softmmu support */
  36
  37/* #define DEBUG_HELPER */
  38#ifdef DEBUG_HELPER
  39#define HELPER_LOG(x...) qemu_log(x)
  40#else
  41#define HELPER_LOG(x...)
  42#endif
  43
  44static inline bool psw_key_valid(CPUS390XState *env, uint8_t psw_key)
  45{
  46    uint16_t pkm = env->cregs[3] >> 16;
  47
  48    if (env->psw.mask & PSW_MASK_PSTATE) {
  49        /* PSW key has range 0..15, it is valid if the bit is 1 in the PKM */
  50        return pkm & (0x80 >> psw_key);
  51    }
  52    return true;
  53}
  54
  55/* Reduce the length so that addr + len doesn't cross a page boundary.  */
  56static inline uint32_t adj_len_to_page(uint32_t len, uint64_t addr)
  57{
  58#ifndef CONFIG_USER_ONLY
  59    if ((addr & ~TARGET_PAGE_MASK) + len - 1 >= TARGET_PAGE_SIZE) {
  60        return -(addr | TARGET_PAGE_MASK);
  61    }
  62#endif
  63    return len;
  64}
  65
  66/* Trigger a SPECIFICATION exception if an address or a length is not
  67   naturally aligned.  */
  68static inline void check_alignment(CPUS390XState *env, uint64_t v,
  69                                   int wordsize, uintptr_t ra)
  70{
  71    if (v % wordsize) {
  72        s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra);
  73    }
  74}
  75
  76/* Load a value from memory according to its size.  */
  77static inline uint64_t cpu_ldusize_data_ra(CPUS390XState *env, uint64_t addr,
  78                                           int wordsize, uintptr_t ra)
  79{
  80    switch (wordsize) {
  81    case 1:
  82        return cpu_ldub_data_ra(env, addr, ra);
  83    case 2:
  84        return cpu_lduw_data_ra(env, addr, ra);
  85    default:
  86        abort();
  87    }
  88}
  89
  90/* Store a to memory according to its size.  */
  91static inline void cpu_stsize_data_ra(CPUS390XState *env, uint64_t addr,
  92                                      uint64_t value, int wordsize,
  93                                      uintptr_t ra)
  94{
  95    switch (wordsize) {
  96    case 1:
  97        cpu_stb_data_ra(env, addr, value, ra);
  98        break;
  99    case 2:
 100        cpu_stw_data_ra(env, addr, value, ra);
 101        break;
 102    default:
 103        abort();
 104    }
 105}
 106
 107static void fast_memset(CPUS390XState *env, uint64_t dest, uint8_t byte,
 108                        uint32_t l, uintptr_t ra)
 109{
 110    int mmu_idx = cpu_mmu_index(env, false);
 111
 112    while (l > 0) {
 113        void *p = tlb_vaddr_to_host(env, dest, MMU_DATA_STORE, mmu_idx);
 114        if (p) {
 115            /* Access to the whole page in write mode granted.  */
 116            uint32_t l_adj = adj_len_to_page(l, dest);
 117            memset(p, byte, l_adj);
 118            dest += l_adj;
 119            l -= l_adj;
 120        } else {
 121            /* We failed to get access to the whole page. The next write
 122               access will likely fill the QEMU TLB for the next iteration.  */
 123            cpu_stb_data_ra(env, dest, byte, ra);
 124            dest++;
 125            l--;
 126        }
 127    }
 128}
 129
 130#ifndef CONFIG_USER_ONLY
 131static void fast_memmove_idx(CPUS390XState *env, uint64_t dest, uint64_t src,
 132                             uint32_t len, int dest_idx, int src_idx,
 133                             uintptr_t ra)
 134{
 135    TCGMemOpIdx oi_dest = make_memop_idx(MO_UB, dest_idx);
 136    TCGMemOpIdx oi_src = make_memop_idx(MO_UB, src_idx);
 137    uint32_t len_adj;
 138    void *src_p;
 139    void *dest_p;
 140    uint8_t x;
 141
 142    while (len > 0) {
 143        src = wrap_address(env, src);
 144        dest = wrap_address(env, dest);
 145        src_p = tlb_vaddr_to_host(env, src, MMU_DATA_LOAD, src_idx);
 146        dest_p = tlb_vaddr_to_host(env, dest, MMU_DATA_STORE, dest_idx);
 147
 148        if (src_p && dest_p) {
 149            /* Access to both whole pages granted.  */
 150            len_adj = adj_len_to_page(adj_len_to_page(len, src), dest);
 151            memmove(dest_p, src_p, len_adj);
 152        } else {
 153            /* We failed to get access to one or both whole pages. The next
 154               read or write access will likely fill the QEMU TLB for the
 155               next iteration.  */
 156            len_adj = 1;
 157            x = helper_ret_ldub_mmu(env, src, oi_src, ra);
 158            helper_ret_stb_mmu(env, dest, x, oi_dest, ra);
 159        }
 160        src += len_adj;
 161        dest += len_adj;
 162        len -= len_adj;
 163    }
 164}
 165
 166static int mmu_idx_from_as(uint8_t as)
 167{
 168    switch (as) {
 169    case AS_PRIMARY:
 170        return MMU_PRIMARY_IDX;
 171    case AS_SECONDARY:
 172        return MMU_SECONDARY_IDX;
 173    case AS_HOME:
 174        return MMU_HOME_IDX;
 175    default:
 176        /* FIXME AS_ACCREG */
 177        g_assert_not_reached();
 178    }
 179}
 180
 181static void fast_memmove_as(CPUS390XState *env, uint64_t dest, uint64_t src,
 182                            uint32_t len, uint8_t dest_as, uint8_t src_as,
 183                            uintptr_t ra)
 184{
 185    int src_idx = mmu_idx_from_as(src_as);
 186    int dest_idx = mmu_idx_from_as(dest_as);
 187
 188    fast_memmove_idx(env, dest, src, len, dest_idx, src_idx, ra);
 189}
 190#endif
 191
 192static void fast_memmove(CPUS390XState *env, uint64_t dest, uint64_t src,
 193                         uint32_t l, uintptr_t ra)
 194{
 195    int mmu_idx = cpu_mmu_index(env, false);
 196
 197    while (l > 0) {
 198        void *src_p = tlb_vaddr_to_host(env, src, MMU_DATA_LOAD, mmu_idx);
 199        void *dest_p = tlb_vaddr_to_host(env, dest, MMU_DATA_STORE, mmu_idx);
 200        if (src_p && dest_p) {
 201            /* Access to both whole pages granted.  */
 202            uint32_t l_adj = adj_len_to_page(l, src);
 203            l_adj = adj_len_to_page(l_adj, dest);
 204            memmove(dest_p, src_p, l_adj);
 205            src += l_adj;
 206            dest += l_adj;
 207            l -= l_adj;
 208        } else {
 209            /* We failed to get access to one or both whole pages. The next
 210               read or write access will likely fill the QEMU TLB for the
 211               next iteration.  */
 212            cpu_stb_data_ra(env, dest, cpu_ldub_data_ra(env, src, ra), ra);
 213            src++;
 214            dest++;
 215            l--;
 216        }
 217    }
 218}
 219
 220/* and on array */
 221static uint32_t do_helper_nc(CPUS390XState *env, uint32_t l, uint64_t dest,
 222                             uint64_t src, uintptr_t ra)
 223{
 224    uint32_t i;
 225    uint8_t c = 0;
 226
 227    HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
 228               __func__, l, dest, src);
 229
 230    for (i = 0; i <= l; i++) {
 231        uint8_t x = cpu_ldub_data_ra(env, src + i, ra);
 232        x &= cpu_ldub_data_ra(env, dest + i, ra);
 233        c |= x;
 234        cpu_stb_data_ra(env, dest + i, x, ra);
 235    }
 236    return c != 0;
 237}
 238
 239uint32_t HELPER(nc)(CPUS390XState *env, uint32_t l, uint64_t dest,
 240                    uint64_t src)
 241{
 242    return do_helper_nc(env, l, dest, src, GETPC());
 243}
 244
 245/* xor on array */
 246static uint32_t do_helper_xc(CPUS390XState *env, uint32_t l, uint64_t dest,
 247                             uint64_t src, uintptr_t ra)
 248{
 249    uint32_t i;
 250    uint8_t c = 0;
 251
 252    HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
 253               __func__, l, dest, src);
 254
 255    /* xor with itself is the same as memset(0) */
 256    if (src == dest) {
 257        fast_memset(env, dest, 0, l + 1, ra);
 258        return 0;
 259    }
 260
 261    for (i = 0; i <= l; i++) {
 262        uint8_t x = cpu_ldub_data_ra(env, src + i, ra);
 263        x ^= cpu_ldub_data_ra(env, dest + i, ra);
 264        c |= x;
 265        cpu_stb_data_ra(env, dest + i, x, ra);
 266    }
 267    return c != 0;
 268}
 269
 270uint32_t HELPER(xc)(CPUS390XState *env, uint32_t l, uint64_t dest,
 271                    uint64_t src)
 272{
 273    return do_helper_xc(env, l, dest, src, GETPC());
 274}
 275
 276/* or on array */
 277static uint32_t do_helper_oc(CPUS390XState *env, uint32_t l, uint64_t dest,
 278                             uint64_t src, uintptr_t ra)
 279{
 280    uint32_t i;
 281    uint8_t c = 0;
 282
 283    HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
 284               __func__, l, dest, src);
 285
 286    for (i = 0; i <= l; i++) {
 287        uint8_t x = cpu_ldub_data_ra(env, src + i, ra);
 288        x |= cpu_ldub_data_ra(env, dest + i, ra);
 289        c |= x;
 290        cpu_stb_data_ra(env, dest + i, x, ra);
 291    }
 292    return c != 0;
 293}
 294
 295uint32_t HELPER(oc)(CPUS390XState *env, uint32_t l, uint64_t dest,
 296                    uint64_t src)
 297{
 298    return do_helper_oc(env, l, dest, src, GETPC());
 299}
 300
 301/* memmove */
 302static uint32_t do_helper_mvc(CPUS390XState *env, uint32_t l, uint64_t dest,
 303                              uint64_t src, uintptr_t ra)
 304{
 305    uint32_t i;
 306
 307    HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
 308               __func__, l, dest, src);
 309
 310    /* mvc and memmove do not behave the same when areas overlap! */
 311    /* mvc with source pointing to the byte after the destination is the
 312       same as memset with the first source byte */
 313    if (dest == src + 1) {
 314        fast_memset(env, dest, cpu_ldub_data_ra(env, src, ra), l + 1, ra);
 315    } else if (dest < src || src + l < dest) {
 316        fast_memmove(env, dest, src, l + 1, ra);
 317    } else {
 318        /* slow version with byte accesses which always work */
 319        for (i = 0; i <= l; i++) {
 320            uint8_t x = cpu_ldub_data_ra(env, src + i, ra);
 321            cpu_stb_data_ra(env, dest + i, x, ra);
 322        }
 323    }
 324
 325    return env->cc_op;
 326}
 327
 328void HELPER(mvc)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
 329{
 330    do_helper_mvc(env, l, dest, src, GETPC());
 331}
 332
 333/* move inverse  */
 334void HELPER(mvcin)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
 335{
 336    uintptr_t ra = GETPC();
 337    int i;
 338
 339    for (i = 0; i <= l; i++) {
 340        uint8_t v = cpu_ldub_data_ra(env, src - i, ra);
 341        cpu_stb_data_ra(env, dest + i, v, ra);
 342    }
 343}
 344
 345/* move numerics  */
 346void HELPER(mvn)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
 347{
 348    uintptr_t ra = GETPC();
 349    int i;
 350
 351    for (i = 0; i <= l; i++) {
 352        uint8_t v = cpu_ldub_data_ra(env, dest + i, ra) & 0xf0;
 353        v |= cpu_ldub_data_ra(env, src + i, ra) & 0x0f;
 354        cpu_stb_data_ra(env, dest + i, v, ra);
 355    }
 356}
 357
 358/* move with offset  */
 359void HELPER(mvo)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
 360{
 361    uintptr_t ra = GETPC();
 362    int len_dest = l >> 4;
 363    int len_src = l & 0xf;
 364    uint8_t byte_dest, byte_src;
 365    int i;
 366
 367    src += len_src;
 368    dest += len_dest;
 369
 370    /* Handle rightmost byte */
 371    byte_src = cpu_ldub_data_ra(env, src, ra);
 372    byte_dest = cpu_ldub_data_ra(env, dest, ra);
 373    byte_dest = (byte_dest & 0x0f) | (byte_src << 4);
 374    cpu_stb_data_ra(env, dest, byte_dest, ra);
 375
 376    /* Process remaining bytes from right to left */
 377    for (i = 1; i <= len_dest; i++) {
 378        byte_dest = byte_src >> 4;
 379        if (len_src - i >= 0) {
 380            byte_src = cpu_ldub_data_ra(env, src - i, ra);
 381        } else {
 382            byte_src = 0;
 383        }
 384        byte_dest |= byte_src << 4;
 385        cpu_stb_data_ra(env, dest - i, byte_dest, ra);
 386    }
 387}
 388
 389/* move zones  */
 390void HELPER(mvz)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
 391{
 392    uintptr_t ra = GETPC();
 393    int i;
 394
 395    for (i = 0; i <= l; i++) {
 396        uint8_t b = cpu_ldub_data_ra(env, dest + i, ra) & 0x0f;
 397        b |= cpu_ldub_data_ra(env, src + i, ra) & 0xf0;
 398        cpu_stb_data_ra(env, dest + i, b, ra);
 399    }
 400}
 401
 402/* compare unsigned byte arrays */
 403static uint32_t do_helper_clc(CPUS390XState *env, uint32_t l, uint64_t s1,
 404                              uint64_t s2, uintptr_t ra)
 405{
 406    uint32_t i;
 407    uint32_t cc = 0;
 408
 409    HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n",
 410               __func__, l, s1, s2);
 411
 412    for (i = 0; i <= l; i++) {
 413        uint8_t x = cpu_ldub_data_ra(env, s1 + i, ra);
 414        uint8_t y = cpu_ldub_data_ra(env, s2 + i, ra);
 415        HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y);
 416        if (x < y) {
 417            cc = 1;
 418            break;
 419        } else if (x > y) {
 420            cc = 2;
 421            break;
 422        }
 423    }
 424
 425    HELPER_LOG("\n");
 426    return cc;
 427}
 428
 429uint32_t HELPER(clc)(CPUS390XState *env, uint32_t l, uint64_t s1, uint64_t s2)
 430{
 431    return do_helper_clc(env, l, s1, s2, GETPC());
 432}
 433
 434/* compare logical under mask */
 435uint32_t HELPER(clm)(CPUS390XState *env, uint32_t r1, uint32_t mask,
 436                     uint64_t addr)
 437{
 438    uintptr_t ra = GETPC();
 439    uint32_t cc = 0;
 440
 441    HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __func__, r1,
 442               mask, addr);
 443
 444    while (mask) {
 445        if (mask & 8) {
 446            uint8_t d = cpu_ldub_data_ra(env, addr, ra);
 447            uint8_t r = extract32(r1, 24, 8);
 448            HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d,
 449                       addr);
 450            if (r < d) {
 451                cc = 1;
 452                break;
 453            } else if (r > d) {
 454                cc = 2;
 455                break;
 456            }
 457            addr++;
 458        }
 459        mask = (mask << 1) & 0xf;
 460        r1 <<= 8;
 461    }
 462
 463    HELPER_LOG("\n");
 464    return cc;
 465}
 466
 467static inline uint64_t get_address(CPUS390XState *env, int reg)
 468{
 469    return wrap_address(env, env->regs[reg]);
 470}
 471
 472static inline void set_address(CPUS390XState *env, int reg, uint64_t address)
 473{
 474    if (env->psw.mask & PSW_MASK_64) {
 475        /* 64-Bit mode */
 476        env->regs[reg] = address;
 477    } else {
 478        if (!(env->psw.mask & PSW_MASK_32)) {
 479            /* 24-Bit mode. According to the PoO it is implementation
 480            dependent if bits 32-39 remain unchanged or are set to
 481            zeros.  Choose the former so that the function can also be
 482            used for TRT.  */
 483            env->regs[reg] = deposit64(env->regs[reg], 0, 24, address);
 484        } else {
 485            /* 31-Bit mode. According to the PoO it is implementation
 486            dependent if bit 32 remains unchanged or is set to zero.
 487            Choose the latter so that the function can also be used for
 488            TRT.  */
 489            address &= 0x7fffffff;
 490            env->regs[reg] = deposit64(env->regs[reg], 0, 32, address);
 491        }
 492    }
 493}
 494
 495static inline uint64_t wrap_length(CPUS390XState *env, uint64_t length)
 496{
 497    if (!(env->psw.mask & PSW_MASK_64)) {
 498        /* 24-Bit and 31-Bit mode */
 499        length &= 0x7fffffff;
 500    }
 501    return length;
 502}
 503
 504static inline uint64_t get_length(CPUS390XState *env, int reg)
 505{
 506    return wrap_length(env, env->regs[reg]);
 507}
 508
 509static inline void set_length(CPUS390XState *env, int reg, uint64_t length)
 510{
 511    if (env->psw.mask & PSW_MASK_64) {
 512        /* 64-Bit mode */
 513        env->regs[reg] = length;
 514    } else {
 515        /* 24-Bit and 31-Bit mode */
 516        env->regs[reg] = deposit64(env->regs[reg], 0, 32, length);
 517    }
 518}
 519
 520/* search string (c is byte to search, r2 is string, r1 end of string) */
 521void HELPER(srst)(CPUS390XState *env, uint32_t r1, uint32_t r2)
 522{
 523    uintptr_t ra = GETPC();
 524    uint64_t end, str;
 525    uint32_t len;
 526    uint8_t v, c = env->regs[0];
 527
 528    /* Bits 32-55 must contain all 0.  */
 529    if (env->regs[0] & 0xffffff00u) {
 530        s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra);
 531    }
 532
 533    str = get_address(env, r2);
 534    end = get_address(env, r1);
 535
 536    /* Lest we fail to service interrupts in a timely manner, limit the
 537       amount of work we're willing to do.  For now, let's cap at 8k.  */
 538    for (len = 0; len < 0x2000; ++len) {
 539        if (str + len == end) {
 540            /* Character not found.  R1 & R2 are unmodified.  */
 541            env->cc_op = 2;
 542            return;
 543        }
 544        v = cpu_ldub_data_ra(env, str + len, ra);
 545        if (v == c) {
 546            /* Character found.  Set R1 to the location; R2 is unmodified.  */
 547            env->cc_op = 1;
 548            set_address(env, r1, str + len);
 549            return;
 550        }
 551    }
 552
 553    /* CPU-determined bytes processed.  Advance R2 to next byte to process.  */
 554    env->cc_op = 3;
 555    set_address(env, r2, str + len);
 556}
 557
 558void HELPER(srstu)(CPUS390XState *env, uint32_t r1, uint32_t r2)
 559{
 560    uintptr_t ra = GETPC();
 561    uint32_t len;
 562    uint16_t v, c = env->regs[0];
 563    uint64_t end, str, adj_end;
 564
 565    /* Bits 32-47 of R0 must be zero.  */
 566    if (env->regs[0] & 0xffff0000u) {
 567        s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra);
 568    }
 569
 570    str = get_address(env, r2);
 571    end = get_address(env, r1);
 572
 573    /* If the LSB of the two addresses differ, use one extra byte.  */
 574    adj_end = end + ((str ^ end) & 1);
 575
 576    /* Lest we fail to service interrupts in a timely manner, limit the
 577       amount of work we're willing to do.  For now, let's cap at 8k.  */
 578    for (len = 0; len < 0x2000; len += 2) {
 579        if (str + len == adj_end) {
 580            /* End of input found.  */
 581            env->cc_op = 2;
 582            return;
 583        }
 584        v = cpu_lduw_data_ra(env, str + len, ra);
 585        if (v == c) {
 586            /* Character found.  Set R1 to the location; R2 is unmodified.  */
 587            env->cc_op = 1;
 588            set_address(env, r1, str + len);
 589            return;
 590        }
 591    }
 592
 593    /* CPU-determined bytes processed.  Advance R2 to next byte to process.  */
 594    env->cc_op = 3;
 595    set_address(env, r2, str + len);
 596}
 597
 598/* unsigned string compare (c is string terminator) */
 599uint64_t HELPER(clst)(CPUS390XState *env, uint64_t c, uint64_t s1, uint64_t s2)
 600{
 601    uintptr_t ra = GETPC();
 602    uint32_t len;
 603
 604    c = c & 0xff;
 605    s1 = wrap_address(env, s1);
 606    s2 = wrap_address(env, s2);
 607
 608    /* Lest we fail to service interrupts in a timely manner, limit the
 609       amount of work we're willing to do.  For now, let's cap at 8k.  */
 610    for (len = 0; len < 0x2000; ++len) {
 611        uint8_t v1 = cpu_ldub_data_ra(env, s1 + len, ra);
 612        uint8_t v2 = cpu_ldub_data_ra(env, s2 + len, ra);
 613        if (v1 == v2) {
 614            if (v1 == c) {
 615                /* Equal.  CC=0, and don't advance the registers.  */
 616                env->cc_op = 0;
 617                env->retxl = s2;
 618                return s1;
 619            }
 620        } else {
 621            /* Unequal.  CC={1,2}, and advance the registers.  Note that
 622               the terminator need not be zero, but the string that contains
 623               the terminator is by definition "low".  */
 624            env->cc_op = (v1 == c ? 1 : v2 == c ? 2 : v1 < v2 ? 1 : 2);
 625            env->retxl = s2 + len;
 626            return s1 + len;
 627        }
 628    }
 629
 630    /* CPU-determined bytes equal; advance the registers.  */
 631    env->cc_op = 3;
 632    env->retxl = s2 + len;
 633    return s1 + len;
 634}
 635
 636/* move page */
 637uint32_t HELPER(mvpg)(CPUS390XState *env, uint64_t r0, uint64_t r1, uint64_t r2)
 638{
 639    /* ??? missing r0 handling, which includes access keys, but more
 640       importantly optional suppression of the exception!  */
 641    fast_memmove(env, r1, r2, TARGET_PAGE_SIZE, GETPC());
 642    return 0; /* data moved */
 643}
 644
 645/* string copy (c is string terminator) */
 646uint64_t HELPER(mvst)(CPUS390XState *env, uint64_t c, uint64_t d, uint64_t s)
 647{
 648    uintptr_t ra = GETPC();
 649    uint32_t len;
 650
 651    c = c & 0xff;
 652    d = wrap_address(env, d);
 653    s = wrap_address(env, s);
 654
 655    /* Lest we fail to service interrupts in a timely manner, limit the
 656       amount of work we're willing to do.  For now, let's cap at 8k.  */
 657    for (len = 0; len < 0x2000; ++len) {
 658        uint8_t v = cpu_ldub_data_ra(env, s + len, ra);
 659        cpu_stb_data_ra(env, d + len, v, ra);
 660        if (v == c) {
 661            /* Complete.  Set CC=1 and advance R1.  */
 662            env->cc_op = 1;
 663            env->retxl = s;
 664            return d + len;
 665        }
 666    }
 667
 668    /* Incomplete.  Set CC=3 and signal to advance R1 and R2.  */
 669    env->cc_op = 3;
 670    env->retxl = s + len;
 671    return d + len;
 672}
 673
 674/* load access registers r1 to r3 from memory at a2 */
 675void HELPER(lam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
 676{
 677    uintptr_t ra = GETPC();
 678    int i;
 679
 680    if (a2 & 0x3) {
 681        /* we either came here by lam or lamy, which have different lengths */
 682        s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, ra);
 683    }
 684
 685    for (i = r1;; i = (i + 1) % 16) {
 686        env->aregs[i] = cpu_ldl_data_ra(env, a2, ra);
 687        a2 += 4;
 688
 689        if (i == r3) {
 690            break;
 691        }
 692    }
 693}
 694
 695/* store access registers r1 to r3 in memory at a2 */
 696void HELPER(stam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
 697{
 698    uintptr_t ra = GETPC();
 699    int i;
 700
 701    if (a2 & 0x3) {
 702        s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra);
 703    }
 704
 705    for (i = r1;; i = (i + 1) % 16) {
 706        cpu_stl_data_ra(env, a2, env->aregs[i], ra);
 707        a2 += 4;
 708
 709        if (i == r3) {
 710            break;
 711        }
 712    }
 713}
 714
 715/* move long helper */
 716static inline uint32_t do_mvcl(CPUS390XState *env,
 717                               uint64_t *dest, uint64_t *destlen,
 718                               uint64_t *src, uint64_t *srclen,
 719                               uint16_t pad, int wordsize, uintptr_t ra)
 720{
 721    uint64_t len = MIN(*srclen, *destlen);
 722    uint32_t cc;
 723
 724    if (*destlen == *srclen) {
 725        cc = 0;
 726    } else if (*destlen < *srclen) {
 727        cc = 1;
 728    } else {
 729        cc = 2;
 730    }
 731
 732    /* Copy the src array */
 733    fast_memmove(env, *dest, *src, len, ra);
 734    *src += len;
 735    *srclen -= len;
 736    *dest += len;
 737    *destlen -= len;
 738
 739    /* Pad the remaining area */
 740    if (wordsize == 1) {
 741        fast_memset(env, *dest, pad, *destlen, ra);
 742        *dest += *destlen;
 743        *destlen = 0;
 744    } else {
 745        /* If remaining length is odd, pad with odd byte first.  */
 746        if (*destlen & 1) {
 747            cpu_stb_data_ra(env, *dest, pad & 0xff, ra);
 748            *dest += 1;
 749            *destlen -= 1;
 750        }
 751        /* The remaining length is even, pad using words.  */
 752        for (; *destlen; *dest += 2, *destlen -= 2) {
 753            cpu_stw_data_ra(env, *dest, pad, ra);
 754        }
 755    }
 756
 757    return cc;
 758}
 759
 760/* move long */
 761uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2)
 762{
 763    uintptr_t ra = GETPC();
 764    uint64_t destlen = env->regs[r1 + 1] & 0xffffff;
 765    uint64_t dest = get_address(env, r1);
 766    uint64_t srclen = env->regs[r2 + 1] & 0xffffff;
 767    uint64_t src = get_address(env, r2);
 768    uint8_t pad = env->regs[r2 + 1] >> 24;
 769    uint32_t cc;
 770
 771    cc = do_mvcl(env, &dest, &destlen, &src, &srclen, pad, 1, ra);
 772
 773    env->regs[r1 + 1] = deposit64(env->regs[r1 + 1], 0, 24, destlen);
 774    env->regs[r2 + 1] = deposit64(env->regs[r2 + 1], 0, 24, srclen);
 775    set_address(env, r1, dest);
 776    set_address(env, r2, src);
 777
 778    return cc;
 779}
 780
 781/* move long extended */
 782uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
 783                       uint32_t r3)
 784{
 785    uintptr_t ra = GETPC();
 786    uint64_t destlen = get_length(env, r1 + 1);
 787    uint64_t dest = get_address(env, r1);
 788    uint64_t srclen = get_length(env, r3 + 1);
 789    uint64_t src = get_address(env, r3);
 790    uint8_t pad = a2;
 791    uint32_t cc;
 792
 793    cc = do_mvcl(env, &dest, &destlen, &src, &srclen, pad, 1, ra);
 794
 795    set_length(env, r1 + 1, destlen);
 796    set_length(env, r3 + 1, srclen);
 797    set_address(env, r1, dest);
 798    set_address(env, r3, src);
 799
 800    return cc;
 801}
 802
 803/* move long unicode */
 804uint32_t HELPER(mvclu)(CPUS390XState *env, uint32_t r1, uint64_t a2,
 805                       uint32_t r3)
 806{
 807    uintptr_t ra = GETPC();
 808    uint64_t destlen = get_length(env, r1 + 1);
 809    uint64_t dest = get_address(env, r1);
 810    uint64_t srclen = get_length(env, r3 + 1);
 811    uint64_t src = get_address(env, r3);
 812    uint16_t pad = a2;
 813    uint32_t cc;
 814
 815    cc = do_mvcl(env, &dest, &destlen, &src, &srclen, pad, 2, ra);
 816
 817    set_length(env, r1 + 1, destlen);
 818    set_length(env, r3 + 1, srclen);
 819    set_address(env, r1, dest);
 820    set_address(env, r3, src);
 821
 822    return cc;
 823}
 824
 825/* compare logical long helper */
 826static inline uint32_t do_clcl(CPUS390XState *env,
 827                               uint64_t *src1, uint64_t *src1len,
 828                               uint64_t *src3, uint64_t *src3len,
 829                               uint16_t pad, uint64_t limit,
 830                               int wordsize, uintptr_t ra)
 831{
 832    uint64_t len = MAX(*src1len, *src3len);
 833    uint32_t cc = 0;
 834
 835    check_alignment(env, *src1len | *src3len, wordsize, ra);
 836
 837    if (!len) {
 838        return cc;
 839    }
 840
 841    /* Lest we fail to service interrupts in a timely manner, limit the
 842       amount of work we're willing to do.  */
 843    if (len > limit) {
 844        len = limit;
 845        cc = 3;
 846    }
 847
 848    for (; len; len -= wordsize) {
 849        uint16_t v1 = pad;
 850        uint16_t v3 = pad;
 851
 852        if (*src1len) {
 853            v1 = cpu_ldusize_data_ra(env, *src1, wordsize, ra);
 854        }
 855        if (*src3len) {
 856            v3 = cpu_ldusize_data_ra(env, *src3, wordsize, ra);
 857        }
 858
 859        if (v1 != v3) {
 860            cc = (v1 < v3) ? 1 : 2;
 861            break;
 862        }
 863
 864        if (*src1len) {
 865            *src1 += wordsize;
 866            *src1len -= wordsize;
 867        }
 868        if (*src3len) {
 869            *src3 += wordsize;
 870            *src3len -= wordsize;
 871        }
 872    }
 873
 874    return cc;
 875}
 876
 877
 878/* compare logical long */
 879uint32_t HELPER(clcl)(CPUS390XState *env, uint32_t r1, uint32_t r2)
 880{
 881    uintptr_t ra = GETPC();
 882    uint64_t src1len = extract64(env->regs[r1 + 1], 0, 24);
 883    uint64_t src1 = get_address(env, r1);
 884    uint64_t src3len = extract64(env->regs[r2 + 1], 0, 24);
 885    uint64_t src3 = get_address(env, r2);
 886    uint8_t pad = env->regs[r2 + 1] >> 24;
 887    uint32_t cc;
 888
 889    cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, -1, 1, ra);
 890
 891    env->regs[r1 + 1] = deposit64(env->regs[r1 + 1], 0, 24, src1len);
 892    env->regs[r2 + 1] = deposit64(env->regs[r2 + 1], 0, 24, src3len);
 893    set_address(env, r1, src1);
 894    set_address(env, r2, src3);
 895
 896    return cc;
 897}
 898
 899/* compare logical long extended memcompare insn with padding */
 900uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
 901                       uint32_t r3)
 902{
 903    uintptr_t ra = GETPC();
 904    uint64_t src1len = get_length(env, r1 + 1);
 905    uint64_t src1 = get_address(env, r1);
 906    uint64_t src3len = get_length(env, r3 + 1);
 907    uint64_t src3 = get_address(env, r3);
 908    uint8_t pad = a2;
 909    uint32_t cc;
 910
 911    cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, 0x2000, 1, ra);
 912
 913    set_length(env, r1 + 1, src1len);
 914    set_length(env, r3 + 1, src3len);
 915    set_address(env, r1, src1);
 916    set_address(env, r3, src3);
 917
 918    return cc;
 919}
 920
 921/* compare logical long unicode memcompare insn with padding */
 922uint32_t HELPER(clclu)(CPUS390XState *env, uint32_t r1, uint64_t a2,
 923                       uint32_t r3)
 924{
 925    uintptr_t ra = GETPC();
 926    uint64_t src1len = get_length(env, r1 + 1);
 927    uint64_t src1 = get_address(env, r1);
 928    uint64_t src3len = get_length(env, r3 + 1);
 929    uint64_t src3 = get_address(env, r3);
 930    uint16_t pad = a2;
 931    uint32_t cc = 0;
 932
 933    cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, 0x1000, 2, ra);
 934
 935    set_length(env, r1 + 1, src1len);
 936    set_length(env, r3 + 1, src3len);
 937    set_address(env, r1, src1);
 938    set_address(env, r3, src3);
 939
 940    return cc;
 941}
 942
 943/* checksum */
 944uint64_t HELPER(cksm)(CPUS390XState *env, uint64_t r1,
 945                      uint64_t src, uint64_t src_len)
 946{
 947    uintptr_t ra = GETPC();
 948    uint64_t max_len, len;
 949    uint64_t cksm = (uint32_t)r1;
 950
 951    /* Lest we fail to service interrupts in a timely manner, limit the
 952       amount of work we're willing to do.  For now, let's cap at 8k.  */
 953    max_len = (src_len > 0x2000 ? 0x2000 : src_len);
 954
 955    /* Process full words as available.  */
 956    for (len = 0; len + 4 <= max_len; len += 4, src += 4) {
 957        cksm += (uint32_t)cpu_ldl_data_ra(env, src, ra);
 958    }
 959
 960    switch (max_len - len) {
 961    case 1:
 962        cksm += cpu_ldub_data_ra(env, src, ra) << 24;
 963        len += 1;
 964        break;
 965    case 2:
 966        cksm += cpu_lduw_data_ra(env, src, ra) << 16;
 967        len += 2;
 968        break;
 969    case 3:
 970        cksm += cpu_lduw_data_ra(env, src, ra) << 16;
 971        cksm += cpu_ldub_data_ra(env, src + 2, ra) << 8;
 972        len += 3;
 973        break;
 974    }
 975
 976    /* Fold the carry from the checksum.  Note that we can see carry-out
 977       during folding more than once (but probably not more than twice).  */
 978    while (cksm > 0xffffffffull) {
 979        cksm = (uint32_t)cksm + (cksm >> 32);
 980    }
 981
 982    /* Indicate whether or not we've processed everything.  */
 983    env->cc_op = (len == src_len ? 0 : 3);
 984
 985    /* Return both cksm and processed length.  */
 986    env->retxl = cksm;
 987    return len;
 988}
 989
 990void HELPER(pack)(CPUS390XState *env, uint32_t len, uint64_t dest, uint64_t src)
 991{
 992    uintptr_t ra = GETPC();
 993    int len_dest = len >> 4;
 994    int len_src = len & 0xf;
 995    uint8_t b;
 996
 997    dest += len_dest;
 998    src += len_src;
 999
1000    /* last byte is special, it only flips the nibbles */
1001    b = cpu_ldub_data_ra(env, src, ra);
1002    cpu_stb_data_ra(env, dest, (b << 4) | (b >> 4), ra);
1003    src--;
1004    len_src--;
1005
1006    /* now pack every value */
1007    while (len_dest > 0) {
1008        b = 0;
1009
1010        if (len_src >= 0) {
1011            b = cpu_ldub_data_ra(env, src, ra) & 0x0f;
1012            src--;
1013            len_src--;
1014        }
1015        if (len_src >= 0) {
1016            b |= cpu_ldub_data_ra(env, src, ra) << 4;
1017            src--;
1018            len_src--;
1019        }
1020
1021        len_dest--;
1022        dest--;
1023        cpu_stb_data_ra(env, dest, b, ra);
1024    }
1025}
1026
1027static inline void do_pkau(CPUS390XState *env, uint64_t dest, uint64_t src,
1028                           uint32_t srclen, int ssize, uintptr_t ra)
1029{
1030    int i;
1031    /* The destination operand is always 16 bytes long.  */
1032    const int destlen = 16;
1033
1034    /* The operands are processed from right to left.  */
1035    src += srclen - 1;
1036    dest += destlen - 1;
1037
1038    for (i = 0; i < destlen; i++) {
1039        uint8_t b = 0;
1040
1041        /* Start with a positive sign */
1042        if (i == 0) {
1043            b = 0xc;
1044        } else if (srclen > ssize) {
1045            b = cpu_ldub_data_ra(env, src, ra) & 0x0f;
1046            src -= ssize;
1047            srclen -= ssize;
1048        }
1049
1050        if (srclen > ssize) {
1051            b |= cpu_ldub_data_ra(env, src, ra) << 4;
1052            src -= ssize;
1053            srclen -= ssize;
1054        }
1055
1056        cpu_stb_data_ra(env, dest, b, ra);
1057        dest--;
1058    }
1059}
1060
1061
1062void HELPER(pka)(CPUS390XState *env, uint64_t dest, uint64_t src,
1063                 uint32_t srclen)
1064{
1065    do_pkau(env, dest, src, srclen, 1, GETPC());
1066}
1067
1068void HELPER(pku)(CPUS390XState *env, uint64_t dest, uint64_t src,
1069                 uint32_t srclen)
1070{
1071    do_pkau(env, dest, src, srclen, 2, GETPC());
1072}
1073
1074void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest,
1075                  uint64_t src)
1076{
1077    uintptr_t ra = GETPC();
1078    int len_dest = len >> 4;
1079    int len_src = len & 0xf;
1080    uint8_t b;
1081    int second_nibble = 0;
1082
1083    dest += len_dest;
1084    src += len_src;
1085
1086    /* last byte is special, it only flips the nibbles */
1087    b = cpu_ldub_data_ra(env, src, ra);
1088    cpu_stb_data_ra(env, dest, (b << 4) | (b >> 4), ra);
1089    src--;
1090    len_src--;
1091
1092    /* now pad every nibble with 0xf0 */
1093
1094    while (len_dest > 0) {
1095        uint8_t cur_byte = 0;
1096
1097        if (len_src > 0) {
1098            cur_byte = cpu_ldub_data_ra(env, src, ra);
1099        }
1100
1101        len_dest--;
1102        dest--;
1103
1104        /* only advance one nibble at a time */
1105        if (second_nibble) {
1106            cur_byte >>= 4;
1107            len_src--;
1108            src--;
1109        }
1110        second_nibble = !second_nibble;
1111
1112        /* digit */
1113        cur_byte = (cur_byte & 0xf);
1114        /* zone bits */
1115        cur_byte |= 0xf0;
1116
1117        cpu_stb_data_ra(env, dest, cur_byte, ra);
1118    }
1119}
1120
1121static inline uint32_t do_unpkau(CPUS390XState *env, uint64_t dest,
1122                                 uint32_t destlen, int dsize, uint64_t src,
1123                                 uintptr_t ra)
1124{
1125    int i;
1126    uint32_t cc;
1127    uint8_t b;
1128    /* The source operand is always 16 bytes long.  */
1129    const int srclen = 16;
1130
1131    /* The operands are processed from right to left.  */
1132    src += srclen - 1;
1133    dest += destlen - dsize;
1134
1135    /* Check for the sign.  */
1136    b = cpu_ldub_data_ra(env, src, ra);
1137    src--;
1138    switch (b & 0xf) {
1139    case 0xa:
1140    case 0xc:
1141    case 0xe ... 0xf:
1142        cc = 0;  /* plus */
1143        break;
1144    case 0xb:
1145    case 0xd:
1146        cc = 1;  /* minus */
1147        break;
1148    default:
1149    case 0x0 ... 0x9:
1150        cc = 3;  /* invalid */
1151        break;
1152    }
1153
1154    /* Now pad every nibble with 0x30, advancing one nibble at a time. */
1155    for (i = 0; i < destlen; i += dsize) {
1156        if (i == (31 * dsize)) {
1157            /* If length is 32/64 bytes, the leftmost byte is 0. */
1158            b = 0;
1159        } else if (i % (2 * dsize)) {
1160            b = cpu_ldub_data_ra(env, src, ra);
1161            src--;
1162        } else {
1163            b >>= 4;
1164        }
1165        cpu_stsize_data_ra(env, dest, 0x30 + (b & 0xf), dsize, ra);
1166        dest -= dsize;
1167    }
1168
1169    return cc;
1170}
1171
1172uint32_t HELPER(unpka)(CPUS390XState *env, uint64_t dest, uint32_t destlen,
1173                       uint64_t src)
1174{
1175    return do_unpkau(env, dest, destlen, 1, src, GETPC());
1176}
1177
1178uint32_t HELPER(unpku)(CPUS390XState *env, uint64_t dest, uint32_t destlen,
1179                       uint64_t src)
1180{
1181    return do_unpkau(env, dest, destlen, 2, src, GETPC());
1182}
1183
1184uint32_t HELPER(tp)(CPUS390XState *env, uint64_t dest, uint32_t destlen)
1185{
1186    uintptr_t ra = GETPC();
1187    uint32_t cc = 0;
1188    int i;
1189
1190    for (i = 0; i < destlen; i++) {
1191        uint8_t b = cpu_ldub_data_ra(env, dest + i, ra);
1192        /* digit */
1193        cc |= (b & 0xf0) > 0x90 ? 2 : 0;
1194
1195        if (i == (destlen - 1)) {
1196            /* sign */
1197            cc |= (b & 0xf) < 0xa ? 1 : 0;
1198        } else {
1199            /* digit */
1200            cc |= (b & 0xf) > 0x9 ? 2 : 0;
1201        }
1202    }
1203
1204    return cc;
1205}
1206
1207static uint32_t do_helper_tr(CPUS390XState *env, uint32_t len, uint64_t array,
1208                             uint64_t trans, uintptr_t ra)
1209{
1210    uint32_t i;
1211
1212    for (i = 0; i <= len; i++) {
1213        uint8_t byte = cpu_ldub_data_ra(env, array + i, ra);
1214        uint8_t new_byte = cpu_ldub_data_ra(env, trans + byte, ra);
1215        cpu_stb_data_ra(env, array + i, new_byte, ra);
1216    }
1217
1218    return env->cc_op;
1219}
1220
1221void HELPER(tr)(CPUS390XState *env, uint32_t len, uint64_t array,
1222                uint64_t trans)
1223{
1224    do_helper_tr(env, len, array, trans, GETPC());
1225}
1226
1227uint64_t HELPER(tre)(CPUS390XState *env, uint64_t array,
1228                     uint64_t len, uint64_t trans)
1229{
1230    uintptr_t ra = GETPC();
1231    uint8_t end = env->regs[0] & 0xff;
1232    uint64_t l = len;
1233    uint64_t i;
1234    uint32_t cc = 0;
1235
1236    if (!(env->psw.mask & PSW_MASK_64)) {
1237        array &= 0x7fffffff;
1238        l = (uint32_t)l;
1239    }
1240
1241    /* Lest we fail to service interrupts in a timely manner, limit the
1242       amount of work we're willing to do.  For now, let's cap at 8k.  */
1243    if (l > 0x2000) {
1244        l = 0x2000;
1245        cc = 3;
1246    }
1247
1248    for (i = 0; i < l; i++) {
1249        uint8_t byte, new_byte;
1250
1251        byte = cpu_ldub_data_ra(env, array + i, ra);
1252
1253        if (byte == end) {
1254            cc = 1;
1255            break;
1256        }
1257
1258        new_byte = cpu_ldub_data_ra(env, trans + byte, ra);
1259        cpu_stb_data_ra(env, array + i, new_byte, ra);
1260    }
1261
1262    env->cc_op = cc;
1263    env->retxl = len - i;
1264    return array + i;
1265}
1266
1267static inline uint32_t do_helper_trt(CPUS390XState *env, int len,
1268                                     uint64_t array, uint64_t trans,
1269                                     int inc, uintptr_t ra)
1270{
1271    int i;
1272
1273    for (i = 0; i <= len; i++) {
1274        uint8_t byte = cpu_ldub_data_ra(env, array + i * inc, ra);
1275        uint8_t sbyte = cpu_ldub_data_ra(env, trans + byte, ra);
1276
1277        if (sbyte != 0) {
1278            set_address(env, 1, array + i * inc);
1279            env->regs[2] = deposit64(env->regs[2], 0, 8, sbyte);
1280            return (i == len) ? 2 : 1;
1281        }
1282    }
1283
1284    return 0;
1285}
1286
1287static uint32_t do_helper_trt_fwd(CPUS390XState *env, uint32_t len,
1288                                  uint64_t array, uint64_t trans,
1289                                  uintptr_t ra)
1290{
1291    return do_helper_trt(env, len, array, trans, 1, ra);
1292}
1293
1294uint32_t HELPER(trt)(CPUS390XState *env, uint32_t len, uint64_t array,
1295                     uint64_t trans)
1296{
1297    return do_helper_trt(env, len, array, trans, 1, GETPC());
1298}
1299
1300static uint32_t do_helper_trt_bkwd(CPUS390XState *env, uint32_t len,
1301                                   uint64_t array, uint64_t trans,
1302                                   uintptr_t ra)
1303{
1304    return do_helper_trt(env, len, array, trans, -1, ra);
1305}
1306
1307uint32_t HELPER(trtr)(CPUS390XState *env, uint32_t len, uint64_t array,
1308                      uint64_t trans)
1309{
1310    return do_helper_trt(env, len, array, trans, -1, GETPC());
1311}
1312
1313/* Translate one/two to one/two */
1314uint32_t HELPER(trXX)(CPUS390XState *env, uint32_t r1, uint32_t r2,
1315                      uint32_t tst, uint32_t sizes)
1316{
1317    uintptr_t ra = GETPC();
1318    int dsize = (sizes & 1) ? 1 : 2;
1319    int ssize = (sizes & 2) ? 1 : 2;
1320    uint64_t tbl = get_address(env, 1);
1321    uint64_t dst = get_address(env, r1);
1322    uint64_t len = get_length(env, r1 + 1);
1323    uint64_t src = get_address(env, r2);
1324    uint32_t cc = 3;
1325    int i;
1326
1327    /* The lower address bits of TBL are ignored.  For TROO, TROT, it's
1328       the low 3 bits (double-word aligned).  For TRTO, TRTT, it's either
1329       the low 12 bits (4K, without ETF2-ENH) or 3 bits (with ETF2-ENH).  */
1330    if (ssize == 2 && !s390_has_feat(S390_FEAT_ETF2_ENH)) {
1331        tbl &= -4096;
1332    } else {
1333        tbl &= -8;
1334    }
1335
1336    check_alignment(env, len, ssize, ra);
1337
1338    /* Lest we fail to service interrupts in a timely manner, */
1339    /* limit the amount of work we're willing to do.   */
1340    for (i = 0; i < 0x2000; i++) {
1341        uint16_t sval = cpu_ldusize_data_ra(env, src, ssize, ra);
1342        uint64_t tble = tbl + (sval * dsize);
1343        uint16_t dval = cpu_ldusize_data_ra(env, tble, dsize, ra);
1344        if (dval == tst) {
1345            cc = 1;
1346            break;
1347        }
1348        cpu_stsize_data_ra(env, dst, dval, dsize, ra);
1349
1350        len -= ssize;
1351        src += ssize;
1352        dst += dsize;
1353
1354        if (len == 0) {
1355            cc = 0;
1356            break;
1357        }
1358    }
1359
1360    set_address(env, r1, dst);
1361    set_length(env, r1 + 1, len);
1362    set_address(env, r2, src);
1363
1364    return cc;
1365}
1366
1367void HELPER(cdsg)(CPUS390XState *env, uint64_t addr,
1368                  uint32_t r1, uint32_t r3)
1369{
1370    uintptr_t ra = GETPC();
1371    Int128 cmpv = int128_make128(env->regs[r1 + 1], env->regs[r1]);
1372    Int128 newv = int128_make128(env->regs[r3 + 1], env->regs[r3]);
1373    Int128 oldv;
1374    uint64_t oldh, oldl;
1375    bool fail;
1376
1377    check_alignment(env, addr, 16, ra);
1378
1379    oldh = cpu_ldq_data_ra(env, addr + 0, ra);
1380    oldl = cpu_ldq_data_ra(env, addr + 8, ra);
1381
1382    oldv = int128_make128(oldl, oldh);
1383    fail = !int128_eq(oldv, cmpv);
1384    if (fail) {
1385        newv = oldv;
1386    }
1387
1388    cpu_stq_data_ra(env, addr + 0, int128_gethi(newv), ra);
1389    cpu_stq_data_ra(env, addr + 8, int128_getlo(newv), ra);
1390
1391    env->cc_op = fail;
1392    env->regs[r1] = int128_gethi(oldv);
1393    env->regs[r1 + 1] = int128_getlo(oldv);
1394}
1395
1396void HELPER(cdsg_parallel)(CPUS390XState *env, uint64_t addr,
1397                           uint32_t r1, uint32_t r3)
1398{
1399    uintptr_t ra = GETPC();
1400    Int128 cmpv = int128_make128(env->regs[r1 + 1], env->regs[r1]);
1401    Int128 newv = int128_make128(env->regs[r3 + 1], env->regs[r3]);
1402    int mem_idx;
1403    TCGMemOpIdx oi;
1404    Int128 oldv;
1405    bool fail;
1406
1407    assert(HAVE_CMPXCHG128);
1408
1409    mem_idx = cpu_mmu_index(env, false);
1410    oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
1411    oldv = helper_atomic_cmpxchgo_be_mmu(env, addr, cmpv, newv, oi, ra);
1412    fail = !int128_eq(oldv, cmpv);
1413
1414    env->cc_op = fail;
1415    env->regs[r1] = int128_gethi(oldv);
1416    env->regs[r1 + 1] = int128_getlo(oldv);
1417}
1418
1419static uint32_t do_csst(CPUS390XState *env, uint32_t r3, uint64_t a1,
1420                        uint64_t a2, bool parallel)
1421{
1422    uint32_t mem_idx = cpu_mmu_index(env, false);
1423    uintptr_t ra = GETPC();
1424    uint32_t fc = extract32(env->regs[0], 0, 8);
1425    uint32_t sc = extract32(env->regs[0], 8, 8);
1426    uint64_t pl = get_address(env, 1) & -16;
1427    uint64_t svh, svl;
1428    uint32_t cc;
1429
1430    /* Sanity check the function code and storage characteristic.  */
1431    if (fc > 1 || sc > 3) {
1432        if (!s390_has_feat(S390_FEAT_COMPARE_AND_SWAP_AND_STORE_2)) {
1433            goto spec_exception;
1434        }
1435        if (fc > 2 || sc > 4 || (fc == 2 && (r3 & 1))) {
1436            goto spec_exception;
1437        }
1438    }
1439
1440    /* Sanity check the alignments.  */
1441    if (extract32(a1, 0, fc + 2) || extract32(a2, 0, sc)) {
1442        goto spec_exception;
1443    }
1444
1445    /* Sanity check writability of the store address.  */
1446#ifndef CONFIG_USER_ONLY
1447    probe_write(env, a2, 0, mem_idx, ra);
1448#endif
1449
1450    /*
1451     * Note that the compare-and-swap is atomic, and the store is atomic,
1452     * but the complete operation is not.  Therefore we do not need to
1453     * assert serial context in order to implement this.  That said,
1454     * restart early if we can't support either operation that is supposed
1455     * to be atomic.
1456     */
1457    if (parallel) {
1458        uint32_t max = 2;
1459#ifdef CONFIG_ATOMIC64
1460        max = 3;
1461#endif
1462        if ((HAVE_CMPXCHG128 ? 0 : fc + 2 > max) ||
1463            (HAVE_ATOMIC128  ? 0 : sc > max)) {
1464            cpu_loop_exit_atomic(env_cpu(env), ra);
1465        }
1466    }
1467
1468    /* All loads happen before all stores.  For simplicity, load the entire
1469       store value area from the parameter list.  */
1470    svh = cpu_ldq_data_ra(env, pl + 16, ra);
1471    svl = cpu_ldq_data_ra(env, pl + 24, ra);
1472
1473    switch (fc) {
1474    case 0:
1475        {
1476            uint32_t nv = cpu_ldl_data_ra(env, pl, ra);
1477            uint32_t cv = env->regs[r3];
1478            uint32_t ov;
1479
1480            if (parallel) {
1481#ifdef CONFIG_USER_ONLY
1482                uint32_t *haddr = g2h(a1);
1483                ov = atomic_cmpxchg__nocheck(haddr, cv, nv);
1484#else
1485                TCGMemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mem_idx);
1486                ov = helper_atomic_cmpxchgl_be_mmu(env, a1, cv, nv, oi, ra);
1487#endif
1488            } else {
1489                ov = cpu_ldl_data_ra(env, a1, ra);
1490                cpu_stl_data_ra(env, a1, (ov == cv ? nv : ov), ra);
1491            }
1492            cc = (ov != cv);
1493            env->regs[r3] = deposit64(env->regs[r3], 32, 32, ov);
1494        }
1495        break;
1496
1497    case 1:
1498        {
1499            uint64_t nv = cpu_ldq_data_ra(env, pl, ra);
1500            uint64_t cv = env->regs[r3];
1501            uint64_t ov;
1502
1503            if (parallel) {
1504#ifdef CONFIG_ATOMIC64
1505# ifdef CONFIG_USER_ONLY
1506                uint64_t *haddr = g2h(a1);
1507                ov = atomic_cmpxchg__nocheck(haddr, cv, nv);
1508# else
1509                TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN, mem_idx);
1510                ov = helper_atomic_cmpxchgq_be_mmu(env, a1, cv, nv, oi, ra);
1511# endif
1512#else
1513                /* Note that we asserted !parallel above.  */
1514                g_assert_not_reached();
1515#endif
1516            } else {
1517                ov = cpu_ldq_data_ra(env, a1, ra);
1518                cpu_stq_data_ra(env, a1, (ov == cv ? nv : ov), ra);
1519            }
1520            cc = (ov != cv);
1521            env->regs[r3] = ov;
1522        }
1523        break;
1524
1525    case 2:
1526        {
1527            uint64_t nvh = cpu_ldq_data_ra(env, pl, ra);
1528            uint64_t nvl = cpu_ldq_data_ra(env, pl + 8, ra);
1529            Int128 nv = int128_make128(nvl, nvh);
1530            Int128 cv = int128_make128(env->regs[r3 + 1], env->regs[r3]);
1531            Int128 ov;
1532
1533            if (!parallel) {
1534                uint64_t oh = cpu_ldq_data_ra(env, a1 + 0, ra);
1535                uint64_t ol = cpu_ldq_data_ra(env, a1 + 8, ra);
1536
1537                ov = int128_make128(ol, oh);
1538                cc = !int128_eq(ov, cv);
1539                if (cc) {
1540                    nv = ov;
1541                }
1542
1543                cpu_stq_data_ra(env, a1 + 0, int128_gethi(nv), ra);
1544                cpu_stq_data_ra(env, a1 + 8, int128_getlo(nv), ra);
1545            } else if (HAVE_CMPXCHG128) {
1546                TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
1547                ov = helper_atomic_cmpxchgo_be_mmu(env, a1, cv, nv, oi, ra);
1548                cc = !int128_eq(ov, cv);
1549            } else {
1550                /* Note that we asserted !parallel above.  */
1551                g_assert_not_reached();
1552            }
1553
1554            env->regs[r3 + 0] = int128_gethi(ov);
1555            env->regs[r3 + 1] = int128_getlo(ov);
1556        }
1557        break;
1558
1559    default:
1560        g_assert_not_reached();
1561    }
1562
1563    /* Store only if the comparison succeeded.  Note that above we use a pair
1564       of 64-bit big-endian loads, so for sc < 3 we must extract the value
1565       from the most-significant bits of svh.  */
1566    if (cc == 0) {
1567        switch (sc) {
1568        case 0:
1569            cpu_stb_data_ra(env, a2, svh >> 56, ra);
1570            break;
1571        case 1:
1572            cpu_stw_data_ra(env, a2, svh >> 48, ra);
1573            break;
1574        case 2:
1575            cpu_stl_data_ra(env, a2, svh >> 32, ra);
1576            break;
1577        case 3:
1578            cpu_stq_data_ra(env, a2, svh, ra);
1579            break;
1580        case 4:
1581            if (!parallel) {
1582                cpu_stq_data_ra(env, a2 + 0, svh, ra);
1583                cpu_stq_data_ra(env, a2 + 8, svl, ra);
1584            } else if (HAVE_ATOMIC128) {
1585                TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
1586                Int128 sv = int128_make128(svl, svh);
1587                helper_atomic_sto_be_mmu(env, a2, sv, oi, ra);
1588            } else {
1589                /* Note that we asserted !parallel above.  */
1590                g_assert_not_reached();
1591            }
1592            break;
1593        default:
1594            g_assert_not_reached();
1595        }
1596    }
1597
1598    return cc;
1599
1600 spec_exception:
1601    s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra);
1602    g_assert_not_reached();
1603}
1604
1605uint32_t HELPER(csst)(CPUS390XState *env, uint32_t r3, uint64_t a1, uint64_t a2)
1606{
1607    return do_csst(env, r3, a1, a2, false);
1608}
1609
1610uint32_t HELPER(csst_parallel)(CPUS390XState *env, uint32_t r3, uint64_t a1,
1611                               uint64_t a2)
1612{
1613    return do_csst(env, r3, a1, a2, true);
1614}
1615
1616#if !defined(CONFIG_USER_ONLY)
1617void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
1618{
1619    uintptr_t ra = GETPC();
1620    bool PERchanged = false;
1621    uint64_t src = a2;
1622    uint32_t i;
1623
1624    if (src & 0x7) {
1625        s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra);
1626    }
1627
1628    for (i = r1;; i = (i + 1) % 16) {
1629        uint64_t val = cpu_ldq_data_ra(env, src, ra);
1630        if (env->cregs[i] != val && i >= 9 && i <= 11) {
1631            PERchanged = true;
1632        }
1633        env->cregs[i] = val;
1634        HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
1635                   i, src, val);
1636        src += sizeof(uint64_t);
1637
1638        if (i == r3) {
1639            break;
1640        }
1641    }
1642
1643    if (PERchanged && env->psw.mask & PSW_MASK_PER) {
1644        s390_cpu_recompute_watchpoints(env_cpu(env));
1645    }
1646
1647    tlb_flush(env_cpu(env));
1648}
1649
1650void HELPER(lctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
1651{
1652    uintptr_t ra = GETPC();
1653    bool PERchanged = false;
1654    uint64_t src = a2;
1655    uint32_t i;
1656
1657    if (src & 0x3) {
1658        s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra);
1659    }
1660
1661    for (i = r1;; i = (i + 1) % 16) {
1662        uint32_t val = cpu_ldl_data_ra(env, src, ra);
1663        if ((uint32_t)env->cregs[i] != val && i >= 9 && i <= 11) {
1664            PERchanged = true;
1665        }
1666        env->cregs[i] = deposit64(env->cregs[i], 0, 32, val);
1667        HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%x\n", i, src, val);
1668        src += sizeof(uint32_t);
1669
1670        if (i == r3) {
1671            break;
1672        }
1673    }
1674
1675    if (PERchanged && env->psw.mask & PSW_MASK_PER) {
1676        s390_cpu_recompute_watchpoints(env_cpu(env));
1677    }
1678
1679    tlb_flush(env_cpu(env));
1680}
1681
1682void HELPER(stctg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
1683{
1684    uintptr_t ra = GETPC();
1685    uint64_t dest = a2;
1686    uint32_t i;
1687
1688    if (dest & 0x7) {
1689        s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra);
1690    }
1691
1692    for (i = r1;; i = (i + 1) % 16) {
1693        cpu_stq_data_ra(env, dest, env->cregs[i], ra);
1694        dest += sizeof(uint64_t);
1695
1696        if (i == r3) {
1697            break;
1698        }
1699    }
1700}
1701
1702void HELPER(stctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
1703{
1704    uintptr_t ra = GETPC();
1705    uint64_t dest = a2;
1706    uint32_t i;
1707
1708    if (dest & 0x3) {
1709        s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra);
1710    }
1711
1712    for (i = r1;; i = (i + 1) % 16) {
1713        cpu_stl_data_ra(env, dest, env->cregs[i], ra);
1714        dest += sizeof(uint32_t);
1715
1716        if (i == r3) {
1717            break;
1718        }
1719    }
1720}
1721
1722uint32_t HELPER(testblock)(CPUS390XState *env, uint64_t real_addr)
1723{
1724    uintptr_t ra = GETPC();
1725    int i;
1726
1727    real_addr = wrap_address(env, real_addr) & TARGET_PAGE_MASK;
1728
1729    for (i = 0; i < TARGET_PAGE_SIZE; i += 8) {
1730        cpu_stq_real_ra(env, real_addr + i, 0, ra);
1731    }
1732
1733    return 0;
1734}
1735
1736uint32_t HELPER(tprot)(CPUS390XState *env, uint64_t a1, uint64_t a2)
1737{
1738    S390CPU *cpu = env_archcpu(env);
1739    CPUState *cs = env_cpu(env);
1740
1741    /*
1742     * TODO: we currently don't handle all access protection types
1743     * (including access-list and key-controlled) as well as AR mode.
1744     */
1745    if (!s390_cpu_virt_mem_check_write(cpu, a1, 0, 1)) {
1746        /* Fetching permitted; storing permitted */
1747        return 0;
1748    }
1749
1750    if (env->int_pgm_code == PGM_PROTECTION) {
1751        /* retry if reading is possible */
1752        cs->exception_index = 0;
1753        if (!s390_cpu_virt_mem_check_read(cpu, a1, 0, 1)) {
1754            /* Fetching permitted; storing not permitted */
1755            return 1;
1756        }
1757    }
1758
1759    switch (env->int_pgm_code) {
1760    case PGM_PROTECTION:
1761        /* Fetching not permitted; storing not permitted */
1762        cs->exception_index = 0;
1763        return 2;
1764    case PGM_ADDRESSING:
1765    case PGM_TRANS_SPEC:
1766        /* exceptions forwarded to the guest */
1767        s390_cpu_virt_mem_handle_exc(cpu, GETPC());
1768        return 0;
1769    }
1770
1771    /* Translation not available */
1772    cs->exception_index = 0;
1773    return 3;
1774}
1775
1776/* insert storage key extended */
1777uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2)
1778{
1779    static S390SKeysState *ss;
1780    static S390SKeysClass *skeyclass;
1781    uint64_t addr = wrap_address(env, r2);
1782    uint8_t key;
1783
1784    if (addr > ram_size) {
1785        return 0;
1786    }
1787
1788    if (unlikely(!ss)) {
1789        ss = s390_get_skeys_device();
1790        skeyclass = S390_SKEYS_GET_CLASS(ss);
1791    }
1792
1793    if (skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key)) {
1794        return 0;
1795    }
1796    return key;
1797}
1798
1799/* set storage key extended */
1800void HELPER(sske)(CPUS390XState *env, uint64_t r1, uint64_t r2)
1801{
1802    static S390SKeysState *ss;
1803    static S390SKeysClass *skeyclass;
1804    uint64_t addr = wrap_address(env, r2);
1805    uint8_t key;
1806
1807    if (addr > ram_size) {
1808        return;
1809    }
1810
1811    if (unlikely(!ss)) {
1812        ss = s390_get_skeys_device();
1813        skeyclass = S390_SKEYS_GET_CLASS(ss);
1814    }
1815
1816    key = (uint8_t) r1;
1817    skeyclass->set_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key);
1818}
1819
1820/* reset reference bit extended */
1821uint32_t HELPER(rrbe)(CPUS390XState *env, uint64_t r2)
1822{
1823    static S390SKeysState *ss;
1824    static S390SKeysClass *skeyclass;
1825    uint8_t re, key;
1826
1827    if (r2 > ram_size) {
1828        return 0;
1829    }
1830
1831    if (unlikely(!ss)) {
1832        ss = s390_get_skeys_device();
1833        skeyclass = S390_SKEYS_GET_CLASS(ss);
1834    }
1835
1836    if (skeyclass->get_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) {
1837        return 0;
1838    }
1839
1840    re = key & (SK_R | SK_C);
1841    key &= ~SK_R;
1842
1843    if (skeyclass->set_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) {
1844        return 0;
1845    }
1846
1847    /*
1848     * cc
1849     *
1850     * 0  Reference bit zero; change bit zero
1851     * 1  Reference bit zero; change bit one
1852     * 2  Reference bit one; change bit zero
1853     * 3  Reference bit one; change bit one
1854     */
1855
1856    return re >> 1;
1857}
1858
1859uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
1860{
1861    uintptr_t ra = GETPC();
1862    int cc = 0, i;
1863
1864    HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1865               __func__, l, a1, a2);
1866
1867    if (l > 256) {
1868        /* max 256 */
1869        l = 256;
1870        cc = 3;
1871    }
1872
1873    /* XXX replace w/ memcpy */
1874    for (i = 0; i < l; i++) {
1875        uint8_t x = cpu_ldub_primary_ra(env, a2 + i, ra);
1876        cpu_stb_secondary_ra(env, a1 + i, x, ra);
1877    }
1878
1879    return cc;
1880}
1881
1882uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
1883{
1884    uintptr_t ra = GETPC();
1885    int cc = 0, i;
1886
1887    HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1888               __func__, l, a1, a2);
1889
1890    if (l > 256) {
1891        /* max 256 */
1892        l = 256;
1893        cc = 3;
1894    }
1895
1896    /* XXX replace w/ memcpy */
1897    for (i = 0; i < l; i++) {
1898        uint8_t x = cpu_ldub_secondary_ra(env, a2 + i, ra);
1899        cpu_stb_primary_ra(env, a1 + i, x, ra);
1900    }
1901
1902    return cc;
1903}
1904
1905void HELPER(idte)(CPUS390XState *env, uint64_t r1, uint64_t r2, uint32_t m4)
1906{
1907    CPUState *cs = env_cpu(env);
1908    const uintptr_t ra = GETPC();
1909    uint64_t table, entry, raddr;
1910    uint16_t entries, i, index = 0;
1911
1912    if (r2 & 0xff000) {
1913        s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra);
1914    }
1915
1916    if (!(r2 & 0x800)) {
1917        /* invalidation-and-clearing operation */
1918        table = r1 & ASCE_ORIGIN;
1919        entries = (r2 & 0x7ff) + 1;
1920
1921        switch (r1 & ASCE_TYPE_MASK) {
1922        case ASCE_TYPE_REGION1:
1923            index = (r2 >> 53) & 0x7ff;
1924            break;
1925        case ASCE_TYPE_REGION2:
1926            index = (r2 >> 42) & 0x7ff;
1927            break;
1928        case ASCE_TYPE_REGION3:
1929            index = (r2 >> 31) & 0x7ff;
1930            break;
1931        case ASCE_TYPE_SEGMENT:
1932            index = (r2 >> 20) & 0x7ff;
1933            break;
1934        }
1935        for (i = 0; i < entries; i++) {
1936            /* addresses are not wrapped in 24/31bit mode but table index is */
1937            raddr = table + ((index + i) & 0x7ff) * sizeof(entry);
1938            entry = cpu_ldq_real_ra(env, raddr, ra);
1939            if (!(entry & REGION_ENTRY_INV)) {
1940                /* we are allowed to not store if already invalid */
1941                entry |= REGION_ENTRY_INV;
1942                cpu_stq_real_ra(env, raddr, entry, ra);
1943            }
1944        }
1945    }
1946
1947    /* We simply flush the complete tlb, therefore we can ignore r3. */
1948    if (m4 & 1) {
1949        tlb_flush(cs);
1950    } else {
1951        tlb_flush_all_cpus_synced(cs);
1952    }
1953}
1954
1955/* invalidate pte */
1956void HELPER(ipte)(CPUS390XState *env, uint64_t pto, uint64_t vaddr,
1957                  uint32_t m4)
1958{
1959    CPUState *cs = env_cpu(env);
1960    const uintptr_t ra = GETPC();
1961    uint64_t page = vaddr & TARGET_PAGE_MASK;
1962    uint64_t pte_addr, pte;
1963
1964    /* Compute the page table entry address */
1965    pte_addr = (pto & SEGMENT_ENTRY_ORIGIN);
1966    pte_addr += (vaddr & VADDR_PX) >> 9;
1967
1968    /* Mark the page table entry as invalid */
1969    pte = cpu_ldq_real_ra(env, pte_addr, ra);
1970    pte |= PAGE_INVALID;
1971    cpu_stq_real_ra(env, pte_addr, pte, ra);
1972
1973    /* XXX we exploit the fact that Linux passes the exact virtual
1974       address here - it's not obliged to! */
1975    if (m4 & 1) {
1976        if (vaddr & ~VADDR_PX) {
1977            tlb_flush_page(cs, page);
1978            /* XXX 31-bit hack */
1979            tlb_flush_page(cs, page ^ 0x80000000);
1980        } else {
1981            /* looks like we don't have a valid virtual address */
1982            tlb_flush(cs);
1983        }
1984    } else {
1985        if (vaddr & ~VADDR_PX) {
1986            tlb_flush_page_all_cpus_synced(cs, page);
1987            /* XXX 31-bit hack */
1988            tlb_flush_page_all_cpus_synced(cs, page ^ 0x80000000);
1989        } else {
1990            /* looks like we don't have a valid virtual address */
1991            tlb_flush_all_cpus_synced(cs);
1992        }
1993    }
1994}
1995
1996/* flush local tlb */
1997void HELPER(ptlb)(CPUS390XState *env)
1998{
1999    tlb_flush(env_cpu(env));
2000}
2001
2002/* flush global tlb */
2003void HELPER(purge)(CPUS390XState *env)
2004{
2005    tlb_flush_all_cpus_synced(env_cpu(env));
2006}
2007
2008/* load using real address */
2009uint64_t HELPER(lura)(CPUS390XState *env, uint64_t addr)
2010{
2011    return cpu_ldl_real_ra(env, wrap_address(env, addr), GETPC());
2012}
2013
2014uint64_t HELPER(lurag)(CPUS390XState *env, uint64_t addr)
2015{
2016    return cpu_ldq_real_ra(env, wrap_address(env, addr), GETPC());
2017}
2018
2019/* store using real address */
2020void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint64_t v1)
2021{
2022    cpu_stl_real_ra(env, wrap_address(env, addr), (uint32_t)v1, GETPC());
2023
2024    if ((env->psw.mask & PSW_MASK_PER) &&
2025        (env->cregs[9] & PER_CR9_EVENT_STORE) &&
2026        (env->cregs[9] & PER_CR9_EVENT_STORE_REAL)) {
2027        /* PSW is saved just before calling the helper.  */
2028        env->per_address = env->psw.addr;
2029        env->per_perc_atmid = PER_CODE_EVENT_STORE_REAL | get_per_atmid(env);
2030    }
2031}
2032
2033void HELPER(sturg)(CPUS390XState *env, uint64_t addr, uint64_t v1)
2034{
2035    cpu_stq_real_ra(env, wrap_address(env, addr), v1, GETPC());
2036
2037    if ((env->psw.mask & PSW_MASK_PER) &&
2038        (env->cregs[9] & PER_CR9_EVENT_STORE) &&
2039        (env->cregs[9] & PER_CR9_EVENT_STORE_REAL)) {
2040        /* PSW is saved just before calling the helper.  */
2041        env->per_address = env->psw.addr;
2042        env->per_perc_atmid = PER_CODE_EVENT_STORE_REAL | get_per_atmid(env);
2043    }
2044}
2045
2046/* load real address */
2047uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr)
2048{
2049    CPUState *cs = env_cpu(env);
2050    uint32_t cc = 0;
2051    uint64_t asc = env->psw.mask & PSW_MASK_ASC;
2052    uint64_t ret;
2053    int old_exc, flags;
2054
2055    /* XXX incomplete - has more corner cases */
2056    if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
2057        s390_program_interrupt(env, PGM_SPECIAL_OP, 2, GETPC());
2058    }
2059
2060    old_exc = cs->exception_index;
2061    if (mmu_translate(env, addr, 0, asc, &ret, &flags, true)) {
2062        cc = 3;
2063    }
2064    if (cs->exception_index == EXCP_PGM) {
2065        ret = env->int_pgm_code | 0x80000000;
2066    } else {
2067        ret |= addr & ~TARGET_PAGE_MASK;
2068    }
2069    cs->exception_index = old_exc;
2070
2071    env->cc_op = cc;
2072    return ret;
2073}
2074#endif
2075
2076/* load pair from quadword */
2077uint64_t HELPER(lpq)(CPUS390XState *env, uint64_t addr)
2078{
2079    uintptr_t ra = GETPC();
2080    uint64_t hi, lo;
2081
2082    check_alignment(env, addr, 16, ra);
2083    hi = cpu_ldq_data_ra(env, addr + 0, ra);
2084    lo = cpu_ldq_data_ra(env, addr + 8, ra);
2085
2086    env->retxl = lo;
2087    return hi;
2088}
2089
2090uint64_t HELPER(lpq_parallel)(CPUS390XState *env, uint64_t addr)
2091{
2092    uintptr_t ra = GETPC();
2093    uint64_t hi, lo;
2094    int mem_idx;
2095    TCGMemOpIdx oi;
2096    Int128 v;
2097
2098    assert(HAVE_ATOMIC128);
2099
2100    mem_idx = cpu_mmu_index(env, false);
2101    oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
2102    v = helper_atomic_ldo_be_mmu(env, addr, oi, ra);
2103    hi = int128_gethi(v);
2104    lo = int128_getlo(v);
2105
2106    env->retxl = lo;
2107    return hi;
2108}
2109
2110/* store pair to quadword */
2111void HELPER(stpq)(CPUS390XState *env, uint64_t addr,
2112                  uint64_t low, uint64_t high)
2113{
2114    uintptr_t ra = GETPC();
2115
2116    check_alignment(env, addr, 16, ra);
2117    cpu_stq_data_ra(env, addr + 0, high, ra);
2118    cpu_stq_data_ra(env, addr + 8, low, ra);
2119}
2120
2121void HELPER(stpq_parallel)(CPUS390XState *env, uint64_t addr,
2122                           uint64_t low, uint64_t high)
2123{
2124    uintptr_t ra = GETPC();
2125    int mem_idx;
2126    TCGMemOpIdx oi;
2127    Int128 v;
2128
2129    assert(HAVE_ATOMIC128);
2130
2131    mem_idx = cpu_mmu_index(env, false);
2132    oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
2133    v = int128_make128(low, high);
2134    helper_atomic_sto_be_mmu(env, addr, v, oi, ra);
2135}
2136
2137/* Execute instruction.  This instruction executes an insn modified with
2138   the contents of r1.  It does not change the executed instruction in memory;
2139   it does not change the program counter.
2140
2141   Perform this by recording the modified instruction in env->ex_value.
2142   This will be noticed by cpu_get_tb_cpu_state and thus tb translation.
2143*/
2144void HELPER(ex)(CPUS390XState *env, uint32_t ilen, uint64_t r1, uint64_t addr)
2145{
2146    uint64_t insn = cpu_lduw_code(env, addr);
2147    uint8_t opc = insn >> 8;
2148
2149    /* Or in the contents of R1[56:63].  */
2150    insn |= r1 & 0xff;
2151
2152    /* Load the rest of the instruction.  */
2153    insn <<= 48;
2154    switch (get_ilen(opc)) {
2155    case 2:
2156        break;
2157    case 4:
2158        insn |= (uint64_t)cpu_lduw_code(env, addr + 2) << 32;
2159        break;
2160    case 6:
2161        insn |= (uint64_t)(uint32_t)cpu_ldl_code(env, addr + 2) << 16;
2162        break;
2163    default:
2164        g_assert_not_reached();
2165    }
2166
2167    /* The very most common cases can be sped up by avoiding a new TB.  */
2168    if ((opc & 0xf0) == 0xd0) {
2169        typedef uint32_t (*dx_helper)(CPUS390XState *, uint32_t, uint64_t,
2170                                      uint64_t, uintptr_t);
2171        static const dx_helper dx[16] = {
2172            [0x0] = do_helper_trt_bkwd,
2173            [0x2] = do_helper_mvc,
2174            [0x4] = do_helper_nc,
2175            [0x5] = do_helper_clc,
2176            [0x6] = do_helper_oc,
2177            [0x7] = do_helper_xc,
2178            [0xc] = do_helper_tr,
2179            [0xd] = do_helper_trt_fwd,
2180        };
2181        dx_helper helper = dx[opc & 0xf];
2182
2183        if (helper) {
2184            uint32_t l = extract64(insn, 48, 8);
2185            uint32_t b1 = extract64(insn, 44, 4);
2186            uint32_t d1 = extract64(insn, 32, 12);
2187            uint32_t b2 = extract64(insn, 28, 4);
2188            uint32_t d2 = extract64(insn, 16, 12);
2189            uint64_t a1 = wrap_address(env, env->regs[b1] + d1);
2190            uint64_t a2 = wrap_address(env, env->regs[b2] + d2);
2191
2192            env->cc_op = helper(env, l, a1, a2, 0);
2193            env->psw.addr += ilen;
2194            return;
2195        }
2196    } else if (opc == 0x0a) {
2197        env->int_svc_code = extract64(insn, 48, 8);
2198        env->int_svc_ilen = ilen;
2199        helper_exception(env, EXCP_SVC);
2200        g_assert_not_reached();
2201    }
2202
2203    /* Record the insn we want to execute as well as the ilen to use
2204       during the execution of the target insn.  This will also ensure
2205       that ex_value is non-zero, which flags that we are in a state
2206       that requires such execution.  */
2207    env->ex_value = insn | ilen;
2208}
2209
2210uint32_t HELPER(mvcos)(CPUS390XState *env, uint64_t dest, uint64_t src,
2211                       uint64_t len)
2212{
2213    const uint8_t psw_key = (env->psw.mask & PSW_MASK_KEY) >> PSW_SHIFT_KEY;
2214    const uint8_t psw_as = (env->psw.mask & PSW_MASK_ASC) >> PSW_SHIFT_ASC;
2215    const uint64_t r0 = env->regs[0];
2216    const uintptr_t ra = GETPC();
2217    uint8_t dest_key, dest_as, dest_k, dest_a;
2218    uint8_t src_key, src_as, src_k, src_a;
2219    uint64_t val;
2220    int cc = 0;
2221
2222    HELPER_LOG("%s dest %" PRIx64 ", src %" PRIx64 ", len %" PRIx64 "\n",
2223               __func__, dest, src, len);
2224
2225    if (!(env->psw.mask & PSW_MASK_DAT)) {
2226        s390_program_interrupt(env, PGM_SPECIAL_OP, 6, ra);
2227    }
2228
2229    /* OAC (operand access control) for the first operand -> dest */
2230    val = (r0 & 0xffff0000ULL) >> 16;
2231    dest_key = (val >> 12) & 0xf;
2232    dest_as = (val >> 6) & 0x3;
2233    dest_k = (val >> 1) & 0x1;
2234    dest_a = val & 0x1;
2235
2236    /* OAC (operand access control) for the second operand -> src */
2237    val = (r0 & 0x0000ffffULL);
2238    src_key = (val >> 12) & 0xf;
2239    src_as = (val >> 6) & 0x3;
2240    src_k = (val >> 1) & 0x1;
2241    src_a = val & 0x1;
2242
2243    if (!dest_k) {
2244        dest_key = psw_key;
2245    }
2246    if (!src_k) {
2247        src_key = psw_key;
2248    }
2249    if (!dest_a) {
2250        dest_as = psw_as;
2251    }
2252    if (!src_a) {
2253        src_as = psw_as;
2254    }
2255
2256    if (dest_a && dest_as == AS_HOME && (env->psw.mask & PSW_MASK_PSTATE)) {
2257        s390_program_interrupt(env, PGM_SPECIAL_OP, 6, ra);
2258    }
2259    if (!(env->cregs[0] & CR0_SECONDARY) &&
2260        (dest_as == AS_SECONDARY || src_as == AS_SECONDARY)) {
2261        s390_program_interrupt(env, PGM_SPECIAL_OP, 6, ra);
2262    }
2263    if (!psw_key_valid(env, dest_key) || !psw_key_valid(env, src_key)) {
2264        s390_program_interrupt(env, PGM_PRIVILEGED, 6, ra);
2265    }
2266
2267    len = wrap_length(env, len);
2268    if (len > 4096) {
2269        cc = 3;
2270        len = 4096;
2271    }
2272
2273    /* FIXME: AR-mode and proper problem state mode (using PSW keys) missing */
2274    if (src_as == AS_ACCREG || dest_as == AS_ACCREG ||
2275        (env->psw.mask & PSW_MASK_PSTATE)) {
2276        qemu_log_mask(LOG_UNIMP, "%s: AR-mode and PSTATE support missing\n",
2277                      __func__);
2278        s390_program_interrupt(env, PGM_ADDRESSING, 6, ra);
2279    }
2280
2281    /* FIXME: a) LAP
2282     *        b) Access using correct keys
2283     *        c) AR-mode
2284     */
2285#ifdef CONFIG_USER_ONLY
2286    /* psw keys are never valid in user mode, we will never reach this */
2287    g_assert_not_reached();
2288#else
2289    fast_memmove_as(env, dest, src, len, dest_as, src_as, ra);
2290#endif
2291
2292    return cc;
2293}
2294
2295/* Decode a Unicode character.  A return value < 0 indicates success, storing
2296   the UTF-32 result into OCHAR and the input length into OLEN.  A return
2297   value >= 0 indicates failure, and the CC value to be returned.  */
2298typedef int (*decode_unicode_fn)(CPUS390XState *env, uint64_t addr,
2299                                 uint64_t ilen, bool enh_check, uintptr_t ra,
2300                                 uint32_t *ochar, uint32_t *olen);
2301
2302/* Encode a Unicode character.  A return value < 0 indicates success, storing
2303   the bytes into ADDR and the output length into OLEN.  A return value >= 0
2304   indicates failure, and the CC value to be returned.  */
2305typedef int (*encode_unicode_fn)(CPUS390XState *env, uint64_t addr,
2306                                 uint64_t ilen, uintptr_t ra, uint32_t c,
2307                                 uint32_t *olen);
2308
2309static int decode_utf8(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2310                       bool enh_check, uintptr_t ra,
2311                       uint32_t *ochar, uint32_t *olen)
2312{
2313    uint8_t s0, s1, s2, s3;
2314    uint32_t c, l;
2315
2316    if (ilen < 1) {
2317        return 0;
2318    }
2319    s0 = cpu_ldub_data_ra(env, addr, ra);
2320    if (s0 <= 0x7f) {
2321        /* one byte character */
2322        l = 1;
2323        c = s0;
2324    } else if (s0 <= (enh_check ? 0xc1 : 0xbf)) {
2325        /* invalid character */
2326        return 2;
2327    } else if (s0 <= 0xdf) {
2328        /* two byte character */
2329        l = 2;
2330        if (ilen < 2) {
2331            return 0;
2332        }
2333        s1 = cpu_ldub_data_ra(env, addr + 1, ra);
2334        c = s0 & 0x1f;
2335        c = (c << 6) | (s1 & 0x3f);
2336        if (enh_check && (s1 & 0xc0) != 0x80) {
2337            return 2;
2338        }
2339    } else if (s0 <= 0xef) {
2340        /* three byte character */
2341        l = 3;
2342        if (ilen < 3) {
2343            return 0;
2344        }
2345        s1 = cpu_ldub_data_ra(env, addr + 1, ra);
2346        s2 = cpu_ldub_data_ra(env, addr + 2, ra);
2347        c = s0 & 0x0f;
2348        c = (c << 6) | (s1 & 0x3f);
2349        c = (c << 6) | (s2 & 0x3f);
2350        /* Fold the byte-by-byte range descriptions in the PoO into
2351           tests against the complete value.  It disallows encodings
2352           that could be smaller, and the UTF-16 surrogates.  */
2353        if (enh_check
2354            && ((s1 & 0xc0) != 0x80
2355                || (s2 & 0xc0) != 0x80
2356                || c < 0x1000
2357                || (c >= 0xd800 && c <= 0xdfff))) {
2358            return 2;
2359        }
2360    } else if (s0 <= (enh_check ? 0xf4 : 0xf7)) {
2361        /* four byte character */
2362        l = 4;
2363        if (ilen < 4) {
2364            return 0;
2365        }
2366        s1 = cpu_ldub_data_ra(env, addr + 1, ra);
2367        s2 = cpu_ldub_data_ra(env, addr + 2, ra);
2368        s3 = cpu_ldub_data_ra(env, addr + 3, ra);
2369        c = s0 & 0x07;
2370        c = (c << 6) | (s1 & 0x3f);
2371        c = (c << 6) | (s2 & 0x3f);
2372        c = (c << 6) | (s3 & 0x3f);
2373        /* See above.  */
2374        if (enh_check
2375            && ((s1 & 0xc0) != 0x80
2376                || (s2 & 0xc0) != 0x80
2377                || (s3 & 0xc0) != 0x80
2378                || c < 0x010000
2379                || c > 0x10ffff)) {
2380            return 2;
2381        }
2382    } else {
2383        /* invalid character */
2384        return 2;
2385    }
2386
2387    *ochar = c;
2388    *olen = l;
2389    return -1;
2390}
2391
2392static int decode_utf16(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2393                        bool enh_check, uintptr_t ra,
2394                        uint32_t *ochar, uint32_t *olen)
2395{
2396    uint16_t s0, s1;
2397    uint32_t c, l;
2398
2399    if (ilen < 2) {
2400        return 0;
2401    }
2402    s0 = cpu_lduw_data_ra(env, addr, ra);
2403    if ((s0 & 0xfc00) != 0xd800) {
2404        /* one word character */
2405        l = 2;
2406        c = s0;
2407    } else {
2408        /* two word character */
2409        l = 4;
2410        if (ilen < 4) {
2411            return 0;
2412        }
2413        s1 = cpu_lduw_data_ra(env, addr + 2, ra);
2414        c = extract32(s0, 6, 4) + 1;
2415        c = (c << 6) | (s0 & 0x3f);
2416        c = (c << 10) | (s1 & 0x3ff);
2417        if (enh_check && (s1 & 0xfc00) != 0xdc00) {
2418            /* invalid surrogate character */
2419            return 2;
2420        }
2421    }
2422
2423    *ochar = c;
2424    *olen = l;
2425    return -1;
2426}
2427
2428static int decode_utf32(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2429                        bool enh_check, uintptr_t ra,
2430                        uint32_t *ochar, uint32_t *olen)
2431{
2432    uint32_t c;
2433
2434    if (ilen < 4) {
2435        return 0;
2436    }
2437    c = cpu_ldl_data_ra(env, addr, ra);
2438    if ((c >= 0xd800 && c <= 0xdbff) || c > 0x10ffff) {
2439        /* invalid unicode character */
2440        return 2;
2441    }
2442
2443    *ochar = c;
2444    *olen = 4;
2445    return -1;
2446}
2447
2448static int encode_utf8(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2449                       uintptr_t ra, uint32_t c, uint32_t *olen)
2450{
2451    uint8_t d[4];
2452    uint32_t l, i;
2453
2454    if (c <= 0x7f) {
2455        /* one byte character */
2456        l = 1;
2457        d[0] = c;
2458    } else if (c <= 0x7ff) {
2459        /* two byte character */
2460        l = 2;
2461        d[1] = 0x80 | extract32(c, 0, 6);
2462        d[0] = 0xc0 | extract32(c, 6, 5);
2463    } else if (c <= 0xffff) {
2464        /* three byte character */
2465        l = 3;
2466        d[2] = 0x80 | extract32(c, 0, 6);
2467        d[1] = 0x80 | extract32(c, 6, 6);
2468        d[0] = 0xe0 | extract32(c, 12, 4);
2469    } else {
2470        /* four byte character */
2471        l = 4;
2472        d[3] = 0x80 | extract32(c, 0, 6);
2473        d[2] = 0x80 | extract32(c, 6, 6);
2474        d[1] = 0x80 | extract32(c, 12, 6);
2475        d[0] = 0xf0 | extract32(c, 18, 3);
2476    }
2477
2478    if (ilen < l) {
2479        return 1;
2480    }
2481    for (i = 0; i < l; ++i) {
2482        cpu_stb_data_ra(env, addr + i, d[i], ra);
2483    }
2484
2485    *olen = l;
2486    return -1;
2487}
2488
2489static int encode_utf16(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2490                        uintptr_t ra, uint32_t c, uint32_t *olen)
2491{
2492    uint16_t d0, d1;
2493
2494    if (c <= 0xffff) {
2495        /* one word character */
2496        if (ilen < 2) {
2497            return 1;
2498        }
2499        cpu_stw_data_ra(env, addr, c, ra);
2500        *olen = 2;
2501    } else {
2502        /* two word character */
2503        if (ilen < 4) {
2504            return 1;
2505        }
2506        d1 = 0xdc00 | extract32(c, 0, 10);
2507        d0 = 0xd800 | extract32(c, 10, 6);
2508        d0 = deposit32(d0, 6, 4, extract32(c, 16, 5) - 1);
2509        cpu_stw_data_ra(env, addr + 0, d0, ra);
2510        cpu_stw_data_ra(env, addr + 2, d1, ra);
2511        *olen = 4;
2512    }
2513
2514    return -1;
2515}
2516
2517static int encode_utf32(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2518                        uintptr_t ra, uint32_t c, uint32_t *olen)
2519{
2520    if (ilen < 4) {
2521        return 1;
2522    }
2523    cpu_stl_data_ra(env, addr, c, ra);
2524    *olen = 4;
2525    return -1;
2526}
2527
2528static inline uint32_t convert_unicode(CPUS390XState *env, uint32_t r1,
2529                                       uint32_t r2, uint32_t m3, uintptr_t ra,
2530                                       decode_unicode_fn decode,
2531                                       encode_unicode_fn encode)
2532{
2533    uint64_t dst = get_address(env, r1);
2534    uint64_t dlen = get_length(env, r1 + 1);
2535    uint64_t src = get_address(env, r2);
2536    uint64_t slen = get_length(env, r2 + 1);
2537    bool enh_check = m3 & 1;
2538    int cc, i;
2539
2540    /* Lest we fail to service interrupts in a timely manner, limit the
2541       amount of work we're willing to do.  For now, let's cap at 256.  */
2542    for (i = 0; i < 256; ++i) {
2543        uint32_t c, ilen, olen;
2544
2545        cc = decode(env, src, slen, enh_check, ra, &c, &ilen);
2546        if (unlikely(cc >= 0)) {
2547            break;
2548        }
2549        cc = encode(env, dst, dlen, ra, c, &olen);
2550        if (unlikely(cc >= 0)) {
2551            break;
2552        }
2553
2554        src += ilen;
2555        slen -= ilen;
2556        dst += olen;
2557        dlen -= olen;
2558        cc = 3;
2559    }
2560
2561    set_address(env, r1, dst);
2562    set_length(env, r1 + 1, dlen);
2563    set_address(env, r2, src);
2564    set_length(env, r2 + 1, slen);
2565
2566    return cc;
2567}
2568
2569uint32_t HELPER(cu12)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2570{
2571    return convert_unicode(env, r1, r2, m3, GETPC(),
2572                           decode_utf8, encode_utf16);
2573}
2574
2575uint32_t HELPER(cu14)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2576{
2577    return convert_unicode(env, r1, r2, m3, GETPC(),
2578                           decode_utf8, encode_utf32);
2579}
2580
2581uint32_t HELPER(cu21)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2582{
2583    return convert_unicode(env, r1, r2, m3, GETPC(),
2584                           decode_utf16, encode_utf8);
2585}
2586
2587uint32_t HELPER(cu24)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2588{
2589    return convert_unicode(env, r1, r2, m3, GETPC(),
2590                           decode_utf16, encode_utf32);
2591}
2592
2593uint32_t HELPER(cu41)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2594{
2595    return convert_unicode(env, r1, r2, m3, GETPC(),
2596                           decode_utf32, encode_utf8);
2597}
2598
2599uint32_t HELPER(cu42)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2600{
2601    return convert_unicode(env, r1, r2, m3, GETPC(),
2602                           decode_utf32, encode_utf16);
2603}
2604
2605void probe_write_access(CPUS390XState *env, uint64_t addr, uint64_t len,
2606                        uintptr_t ra)
2607{
2608#ifdef CONFIG_USER_ONLY
2609    if (!h2g_valid(addr) || !h2g_valid(addr + len - 1) ||
2610        page_check_range(addr, len, PAGE_WRITE) < 0) {
2611        s390_program_interrupt(env, PGM_ADDRESSING, ILEN_AUTO, ra);
2612    }
2613#else
2614    /* test the actual access, not just any access to the page due to LAP */
2615    while (len) {
2616        const uint64_t pagelen = -(addr | -TARGET_PAGE_MASK);
2617        const uint64_t curlen = MIN(pagelen, len);
2618
2619        probe_write(env, addr, curlen, cpu_mmu_index(env, false), ra);
2620        addr = wrap_address(env, addr + curlen);
2621        len -= curlen;
2622    }
2623#endif
2624}
2625
2626void HELPER(probe_write_access)(CPUS390XState *env, uint64_t addr, uint64_t len)
2627{
2628    probe_write_access(env, addr, len, GETPC());
2629}
2630