“a0fa2cb8ccf0b73cfd3ac01d557401a2303c0de4”上不存在“target/s390x/misc_helper.c”
misc_helper.c 17.8 KB
Newer Older
A
Alexander Graf 已提交
1
/*
2
 *  S/390 misc helper routines
A
Alexander Graf 已提交
3
 *
A
Alexander Graf 已提交
4
 *  Copyright (c) 2009 Ulrich Hecht
A
Alexander Graf 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17
 *  Copyright (c) 2009 Alexander Graf
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * 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/>.
A
Alexander Graf 已提交
19 20
 */

P
Peter Maydell 已提交
21
#include "qemu/osdep.h"
B
Blue Swirl 已提交
22
#include "cpu.h"
23
#include "exec/memory.h"
24
#include "qemu/host-utils.h"
25
#include "exec/helper-proto.h"
26
#include "sysemu/kvm.h"
27
#include "qemu/timer.h"
28
#include "exec/address-spaces.h"
29 30 31
#ifdef CONFIG_KVM
#include <linux/kvm.h>
#endif
32
#include "exec/exec-all.h"
P
Paolo Bonzini 已提交
33
#include "exec/cpu_ldst.h"
A
Alexander Graf 已提交
34

B
Blue Swirl 已提交
35
#if !defined(CONFIG_USER_ONLY)
36
#include "hw/watchdog/wdt_diag288.h"
37
#include "sysemu/cpus.h"
38
#include "sysemu/sysemu.h"
39
#include "hw/s390x/ebcdic.h"
40
#include "hw/s390x/ipl.h"
A
Alexander Graf 已提交
41
#endif
42

A
Alexander Graf 已提交
43 44 45 46 47 48 49
/* #define DEBUG_HELPER */
#ifdef DEBUG_HELPER
#define HELPER_LOG(x...) qemu_log(x)
#else
#define HELPER_LOG(x...)
#endif

50 51 52 53
/* Raise an exception dynamically from a helper function.  */
void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp,
                                     uintptr_t retaddr)
{
54
    CPUState *cs = CPU(s390_env_get_cpu(env));
55 56
    int t;

57
    cs->exception_index = EXCP_PGM;
58 59 60
    env->int_pgm_code = excp;

    /* Use the (ultimate) callers address to find the insn that trapped.  */
61
    cpu_restore_state(cs, retaddr);
62 63 64 65

    /* Advance past the insn.  */
    t = cpu_ldub_code(env, env->psw.addr);
    env->int_pgm_ilen = t = get_ilen(t);
66
    env->psw.addr += t;
67

68
    cpu_loop_exit(cs);
69 70
}

71
/* Raise an exception statically from a TB.  */
72
void HELPER(exception)(CPUS390XState *env, uint32_t excp)
A
Alexander Graf 已提交
73
{
74 75
    CPUState *cs = CPU(s390_env_get_cpu(env));

B
Blue Swirl 已提交
76
    HELPER_LOG("%s: exception %d\n", __func__, excp);
77
    cs->exception_index = excp;
78
    cpu_loop_exit(cs);
A
Alexander Graf 已提交
79 80 81
}

#ifndef CONFIG_USER_ONLY
82

83
void program_interrupt(CPUS390XState *env, uint32_t code, int ilen)
A
Alexander Graf 已提交
84
{
85 86
    S390CPU *cpu = s390_env_get_cpu(env);

87 88
    qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
                  env->psw.addr);
A
Alexander Graf 已提交
89 90

    if (kvm_enabled()) {
91
#ifdef CONFIG_KVM
92 93 94 95 96 97
        struct kvm_s390_irq irq = {
            .type = KVM_S390_PROGRAM_INT,
            .u.pgm.code = code,
        };

        kvm_s390_vcpu_interrupt(cpu, &irq);
98
#endif
A
Alexander Graf 已提交
99
    } else {
100 101
        CPUState *cs = CPU(cpu);

A
Alexander Graf 已提交
102
        env->int_pgm_code = code;
103
        env->int_pgm_ilen = ilen;
104
        cs->exception_index = EXCP_PGM;
105
        cpu_loop_exit(cs);
A
Alexander Graf 已提交
106 107 108 109
    }
}

/* SCLP service call */
R
Richard Henderson 已提交
110
uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2)
A
Alexander Graf 已提交
111
{
112
    int r = sclp_service_call(env, r1, r2);
113 114 115 116 117
    if (r < 0) {
        program_interrupt(env, -r, 4);
        return 0;
    }
    return r;
A
Alexander Graf 已提交
118 119
}

120
#ifndef CONFIG_USER_ONLY
121 122 123
static int modified_clear_reset(S390CPU *cpu)
{
    S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
124
    CPUState *t;
125 126 127

    pause_all_vcpus();
    cpu_synchronize_all_states();
128
    CPU_FOREACH(t) {
129
        run_on_cpu(t, s390_do_cpu_full_reset, RUN_ON_CPU_NULL);
130
    }
131
    s390_cmma_reset();
132
    subsystem_reset();
133
    s390_crypto_reset();
134 135 136 137 138 139
    scc->load_normal(CPU(cpu));
    cpu_synchronize_all_post_reset();
    resume_all_vcpus();
    return 0;
}

140 141 142
static int load_normal_reset(S390CPU *cpu)
{
    S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
143
    CPUState *t;
144 145 146

    pause_all_vcpus();
    cpu_synchronize_all_states();
147
    CPU_FOREACH(t) {
148
        run_on_cpu(t, s390_do_cpu_reset, RUN_ON_CPU_NULL);
149
    }
150
    s390_cmma_reset();
151
    subsystem_reset();
152 153 154 155 156 157 158
    scc->initial_cpu_reset(CPU(cpu));
    scc->load_normal(CPU(cpu));
    cpu_synchronize_all_post_reset();
    resume_all_vcpus();
    return 0;
}

159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3)
{
    uint64_t func = env->regs[r1];
    uint64_t timeout = env->regs[r1 + 1];
    uint64_t action = env->regs[r3];
    Object *obj;
    DIAG288State *diag288;
    DIAG288Class *diag288_class;

    if (r1 % 2 || action != 0) {
        return -1;
    }

    /* Timeout must be more than 15 seconds except for timer deletion */
    if (func != WDT_DIAG288_CANCEL && timeout < 15) {
        return -1;
    }

    obj = object_resolve_path_type("", TYPE_WDT_DIAG288, NULL);
    if (!obj) {
        return -1;
    }

    diag288 = DIAG288(obj);
    diag288_class = DIAG288_GET_CLASS(diag288);
    return diag288_class->handle_timer(diag288, func, timeout);
}

187
#define DIAG_308_RC_OK              0x0001
188 189
#define DIAG_308_RC_NO_CONF         0x0102
#define DIAG_308_RC_INVALID         0x0402
190

191 192 193 194
void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3)
{
    uint64_t addr =  env->regs[r1];
    uint64_t subcode = env->regs[r3];
195
    IplParameterBlock *iplb;
196 197 198 199 200 201 202 203 204 205 206 207

    if (env->psw.mask & PSW_MASK_PSTATE) {
        program_interrupt(env, PGM_PRIVILEGED, ILEN_LATER_INC);
        return;
    }

    if ((subcode & ~0x0ffffULL) || (subcode > 6)) {
        program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
        return;
    }

    switch (subcode) {
208 209
    case 0:
        modified_clear_reset(s390_env_get_cpu(env));
210 211 212
        if (tcg_enabled()) {
            cpu_loop_exit(CPU(s390_env_get_cpu(env)));
        }
213
        break;
214 215
    case 1:
        load_normal_reset(s390_env_get_cpu(env));
216 217 218
        if (tcg_enabled()) {
            cpu_loop_exit(CPU(s390_env_get_cpu(env)));
        }
219
        break;
220 221 222 223 224 225
    case 3:
        s390_reipl_request();
        if (tcg_enabled()) {
            cpu_loop_exit(CPU(s390_env_get_cpu(env)));
        }
        break;
226 227 228 229 230
    case 5:
        if ((r1 & 1) || (addr & 0x0fffULL)) {
            program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
            return;
        }
231 232 233 234 235
        if (!address_space_access_valid(&address_space_memory, addr,
                                        sizeof(IplParameterBlock), false)) {
            program_interrupt(env, PGM_ADDRESSING, ILEN_LATER_INC);
            return;
        }
236
        iplb = g_malloc0(sizeof(IplParameterBlock));
237 238 239 240 241 242 243 244 245 246 247 248 249
        cpu_physical_memory_read(addr, iplb, sizeof(iplb->len));
        if (!iplb_valid_len(iplb)) {
            env->regs[r1 + 1] = DIAG_308_RC_INVALID;
            goto out;
        }

        cpu_physical_memory_read(addr, iplb, be32_to_cpu(iplb->len));

        if (!iplb_valid_ccw(iplb) && !iplb_valid_fcp(iplb)) {
            env->regs[r1 + 1] = DIAG_308_RC_INVALID;
            goto out;
        }

250 251
        s390_ipl_update_diag308(iplb);
        env->regs[r1 + 1] = DIAG_308_RC_OK;
252
out:
253
        g_free(iplb);
254 255 256 257 258 259
        return;
    case 6:
        if ((r1 & 1) || (addr & 0x0fffULL)) {
            program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
            return;
        }
260 261 262 263 264 265 266
        if (!address_space_access_valid(&address_space_memory, addr,
                                        sizeof(IplParameterBlock), true)) {
            program_interrupt(env, PGM_ADDRESSING, ILEN_LATER_INC);
            return;
        }
        iplb = s390_ipl_get_iplb();
        if (iplb) {
267
            cpu_physical_memory_write(addr, iplb, be32_to_cpu(iplb->len));
268 269 270 271
            env->regs[r1 + 1] = DIAG_308_RC_OK;
        } else {
            env->regs[r1 + 1] = DIAG_308_RC_NO_CONF;
        }
272 273 274 275 276 277 278 279
        return;
    default:
        hw_error("Unhandled diag308 subcode %" PRIx64, subcode);
        break;
    }
}
#endif

280
void HELPER(diag)(CPUS390XState *env, uint32_t r1, uint32_t r3, uint32_t num)
A
Alexander Graf 已提交
281 282 283 284 285 286
{
    uint64_t r;

    switch (num) {
    case 0x500:
        /* KVM hypercall */
287
        r = s390_virtio_hypercall(env);
A
Alexander Graf 已提交
288 289 290 291 292 293 294
        break;
    case 0x44:
        /* yield */
        r = 0;
        break;
    case 0x308:
        /* ipl */
295
        handle_diag_308(env, r1, r3);
A
Alexander Graf 已提交
296 297 298 299 300 301 302 303
        r = 0;
        break;
    default:
        r = -1;
        break;
    }

    if (r) {
304
        program_interrupt(env, PGM_OPERATION, ILEN_LATER_INC);
A
Alexander Graf 已提交
305 306 307 308
    }
}

/* Set Prefix */
309
void HELPER(spx)(CPUS390XState *env, uint64_t a1)
A
Alexander Graf 已提交
310
{
311
    CPUState *cs = CPU(s390_env_get_cpu(env));
312
    uint32_t prefix = a1 & 0x7fffe000;
313

314
    env->psa = prefix;
P
Paolo Bonzini 已提交
315
    HELPER_LOG("prefix: %#x\n", prefix);
316 317
    tlb_flush_page(cs, 0);
    tlb_flush_page(cs, TARGET_PAGE_SIZE);
A
Alexander Graf 已提交
318 319
}

320 321
/* Store Clock */
uint64_t HELPER(stck)(CPUS390XState *env)
A
Alexander Graf 已提交
322 323 324 325
{
    uint64_t time;

    time = env->tod_offset +
326
        time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - env->tod_basetime);
A
Alexander Graf 已提交
327 328 329 330 331

    return time;
}

/* Set Clock Comparator */
332
void HELPER(sckc)(CPUS390XState *env, uint64_t time)
A
Alexander Graf 已提交
333 334 335 336 337
{
    if (time == -1ULL) {
        return;
    }

338 339
    env->ckc = time;

340 341 342
    /* difference between origins */
    time -= env->tod_offset;

A
Alexander Graf 已提交
343
    /* nanoseconds */
344
    time = tod2time(time);
A
Alexander Graf 已提交
345

346
    timer_mod(env->tod_timer, env->tod_basetime + time);
A
Alexander Graf 已提交
347 348 349
}

/* Store Clock Comparator */
350
uint64_t HELPER(stckc)(CPUS390XState *env)
A
Alexander Graf 已提交
351
{
352
    return env->ckc;
A
Alexander Graf 已提交
353 354 355
}

/* Set CPU Timer */
356
void HELPER(spt)(CPUS390XState *env, uint64_t time)
A
Alexander Graf 已提交
357 358 359 360 361 362
{
    if (time == -1ULL) {
        return;
    }

    /* nanoseconds */
363
    time = tod2time(time);
A
Alexander Graf 已提交
364

365 366 367
    env->cputm = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time;

    timer_mod(env->cpu_timer, env->cputm);
A
Alexander Graf 已提交
368 369 370
}

/* Store CPU Timer */
371
uint64_t HELPER(stpt)(CPUS390XState *env)
A
Alexander Graf 已提交
372
{
373
    return time2tod(env->cputm - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
A
Alexander Graf 已提交
374 375 376
}

/* Store System Information */
R
Richard Henderson 已提交
377 378
uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0,
                      uint64_t r0, uint64_t r1)
A
Alexander Graf 已提交
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407
{
    int cc = 0;
    int sel1, sel2;

    if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 &&
        ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) {
        /* valid function code, invalid reserved bits */
        program_interrupt(env, PGM_SPECIFICATION, 2);
    }

    sel1 = r0 & STSI_R0_SEL1_MASK;
    sel2 = r1 & STSI_R1_SEL2_MASK;

    /* XXX: spec exception if sysib is not 4k-aligned */

    switch (r0 & STSI_LEVEL_MASK) {
    case STSI_LEVEL_1:
        if ((sel1 == 1) && (sel2 == 1)) {
            /* Basic Machine Configuration */
            struct sysib_111 sysib;

            memset(&sysib, 0, sizeof(sysib));
            ebcdic_put(sysib.manuf, "QEMU            ", 16);
            /* same as machine type number in STORE CPU ID */
            ebcdic_put(sysib.type, "QEMU", 4);
            /* same as model number in STORE CPU ID */
            ebcdic_put(sysib.model, "QEMU            ", 16);
            ebcdic_put(sysib.sequence, "QEMU            ", 16);
            ebcdic_put(sysib.plant, "QEMU", 4);
408
            cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
A
Alexander Graf 已提交
409 410 411 412 413 414 415 416 417
        } else if ((sel1 == 2) && (sel2 == 1)) {
            /* Basic Machine CPU */
            struct sysib_121 sysib;

            memset(&sysib, 0, sizeof(sysib));
            /* XXX make different for different CPUs? */
            ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
            ebcdic_put(sysib.plant, "QEMU", 4);
            stw_p(&sysib.cpu_addr, env->cpu_num);
418
            cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
A
Alexander Graf 已提交
419 420 421 422 423 424 425 426 427 428 429
        } else if ((sel1 == 2) && (sel2 == 2)) {
            /* Basic Machine CPUs */
            struct sysib_122 sysib;

            memset(&sysib, 0, sizeof(sysib));
            stl_p(&sysib.capability, 0x443afc29);
            /* XXX change when SMP comes */
            stw_p(&sysib.total_cpus, 1);
            stw_p(&sysib.active_cpus, 1);
            stw_p(&sysib.standby_cpus, 0);
            stw_p(&sysib.reserved_cpus, 0);
430
            cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
A
Alexander Graf 已提交
431 432 433 434 435
        } else {
            cc = 3;
        }
        break;
    case STSI_LEVEL_2:
B
Blue Swirl 已提交
436 437 438 439 440 441 442 443 444 445 446
        {
            if ((sel1 == 2) && (sel2 == 1)) {
                /* LPAR CPU */
                struct sysib_221 sysib;

                memset(&sysib, 0, sizeof(sysib));
                /* XXX make different for different CPUs? */
                ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
                ebcdic_put(sysib.plant, "QEMU", 4);
                stw_p(&sysib.cpu_addr, env->cpu_num);
                stw_p(&sysib.cpu_id, 0);
447
                cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
B
Blue Swirl 已提交
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463
            } else if ((sel1 == 2) && (sel2 == 2)) {
                /* LPAR CPUs */
                struct sysib_222 sysib;

                memset(&sysib, 0, sizeof(sysib));
                stw_p(&sysib.lpar_num, 0);
                sysib.lcpuc = 0;
                /* XXX change when SMP comes */
                stw_p(&sysib.total_cpus, 1);
                stw_p(&sysib.conf_cpus, 1);
                stw_p(&sysib.standby_cpus, 0);
                stw_p(&sysib.reserved_cpus, 0);
                ebcdic_put(sysib.name, "QEMU    ", 8);
                stl_p(&sysib.caf, 1000);
                stw_p(&sysib.dedicated_cpus, 0);
                stw_p(&sysib.shared_cpus, 0);
464
                cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
B
Blue Swirl 已提交
465 466 467 468
            } else {
                cc = 3;
            }
            break;
A
Alexander Graf 已提交
469 470
        }
    case STSI_LEVEL_3:
B
Blue Swirl 已提交
471 472 473 474 475 476 477 478 479 480 481 482 483 484 485
        {
            if ((sel1 == 2) && (sel2 == 2)) {
                /* VM CPUs */
                struct sysib_322 sysib;

                memset(&sysib, 0, sizeof(sysib));
                sysib.count = 1;
                /* XXX change when SMP comes */
                stw_p(&sysib.vm[0].total_cpus, 1);
                stw_p(&sysib.vm[0].conf_cpus, 1);
                stw_p(&sysib.vm[0].standby_cpus, 0);
                stw_p(&sysib.vm[0].reserved_cpus, 0);
                ebcdic_put(sysib.vm[0].name, "KVMguest", 8);
                stl_p(&sysib.vm[0].caf, 1000);
                ebcdic_put(sysib.vm[0].cpi, "KVM/Linux       ", 16);
486
                cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
B
Blue Swirl 已提交
487 488 489 490
            } else {
                cc = 3;
            }
            break;
A
Alexander Graf 已提交
491 492 493 494 495 496 497 498 499 500 501 502
        }
    case STSI_LEVEL_CURRENT:
        env->regs[0] = STSI_LEVEL_3;
        break;
    default:
        cc = 3;
        break;
    }

    return cc;
}

503 504
uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1,
                      uint64_t cpu_addr)
A
Alexander Graf 已提交
505
{
506
    int cc = SIGP_CC_ORDER_CODE_ACCEPTED;
A
Alexander Graf 已提交
507 508

    HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n",
B
Blue Swirl 已提交
509
               __func__, order_code, r1, cpu_addr);
A
Alexander Graf 已提交
510

B
Blue Swirl 已提交
511
    /* Remember: Use "R1 or R1 + 1, whichever is the odd-numbered register"
A
Alexander Graf 已提交
512 513 514 515 516 517 518 519 520 521 522 523 524 525 526
       as parameter (input). Status (output) is always R1. */

    switch (order_code) {
    case SIGP_SET_ARCH:
        /* switch arch */
        break;
    case SIGP_SENSE:
        /* enumerate CPU status */
        if (cpu_addr) {
            /* XXX implement when SMP comes */
            return 3;
        }
        env->regs[r1] &= 0xffffffff00000000ULL;
        cc = 1;
        break;
B
Blue Swirl 已提交
527
#if !defined(CONFIG_USER_ONLY)
528 529
    case SIGP_RESTART:
        qemu_system_reset_request();
530
        cpu_loop_exit(CPU(s390_env_get_cpu(env)));
531 532 533
        break;
    case SIGP_STOP:
        qemu_system_shutdown_request();
534
        cpu_loop_exit(CPU(s390_env_get_cpu(env)));
535 536
        break;
#endif
A
Alexander Graf 已提交
537 538 539
    default:
        /* unknown sigp */
        fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code);
540
        cc = SIGP_CC_NOT_OPERATIONAL;
A
Alexander Graf 已提交
541 542 543 544 545
    }

    return cc;
}
#endif
546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607

#ifndef CONFIG_USER_ONLY
void HELPER(xsch)(CPUS390XState *env, uint64_t r1)
{
    S390CPU *cpu = s390_env_get_cpu(env);
    ioinst_handle_xsch(cpu, r1);
}

void HELPER(csch)(CPUS390XState *env, uint64_t r1)
{
    S390CPU *cpu = s390_env_get_cpu(env);
    ioinst_handle_csch(cpu, r1);
}

void HELPER(hsch)(CPUS390XState *env, uint64_t r1)
{
    S390CPU *cpu = s390_env_get_cpu(env);
    ioinst_handle_hsch(cpu, r1);
}

void HELPER(msch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
{
    S390CPU *cpu = s390_env_get_cpu(env);
    ioinst_handle_msch(cpu, r1, inst >> 16);
}

void HELPER(rchp)(CPUS390XState *env, uint64_t r1)
{
    S390CPU *cpu = s390_env_get_cpu(env);
    ioinst_handle_rchp(cpu, r1);
}

void HELPER(rsch)(CPUS390XState *env, uint64_t r1)
{
    S390CPU *cpu = s390_env_get_cpu(env);
    ioinst_handle_rsch(cpu, r1);
}

void HELPER(ssch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
{
    S390CPU *cpu = s390_env_get_cpu(env);
    ioinst_handle_ssch(cpu, r1, inst >> 16);
}

void HELPER(stsch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
{
    S390CPU *cpu = s390_env_get_cpu(env);
    ioinst_handle_stsch(cpu, r1, inst >> 16);
}

void HELPER(tsch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
{
    S390CPU *cpu = s390_env_get_cpu(env);
    ioinst_handle_tsch(cpu, r1, inst >> 16);
}

void HELPER(chsc)(CPUS390XState *env, uint64_t inst)
{
    S390CPU *cpu = s390_env_get_cpu(env);
    ioinst_handle_chsc(cpu, inst >> 16);
}
#endif
608 609 610 611 612 613 614 615 616 617 618 619 620 621

#ifndef CONFIG_USER_ONLY
void HELPER(per_check_exception)(CPUS390XState *env)
{
    CPUState *cs = CPU(s390_env_get_cpu(env));

    if (env->per_perc_atmid) {
        env->int_pgm_code = PGM_PER;
        env->int_pgm_ilen = get_ilen(cpu_ldub_code(env, env->per_address));

        cs->exception_index = EXCP_PGM;
        cpu_loop_exit(cs);
    }
}
622 623 624 625 626 627 628 629 630 631 632

void HELPER(per_branch)(CPUS390XState *env, uint64_t from, uint64_t to)
{
    if ((env->cregs[9] & PER_CR9_EVENT_BRANCH)) {
        if (!(env->cregs[9] & PER_CR9_CONTROL_BRANCH_ADDRESS)
            || get_per_in_range(env, to)) {
            env->per_address = from;
            env->per_perc_atmid = PER_CODE_EVENT_BRANCH | get_per_atmid(env);
        }
    }
}
633 634 635 636 637 638

void HELPER(per_ifetch)(CPUS390XState *env, uint64_t addr)
{
    if ((env->cregs[9] & PER_CR9_EVENT_IFETCH) && get_per_in_range(env, addr)) {
        env->per_address = addr;
        env->per_perc_atmid = PER_CODE_EVENT_IFETCH | get_per_atmid(env);
639 640 641 642 643 644 645 646 647 648 649 650

        /* If the instruction has to be nullified, trigger the
           exception immediately. */
        if (env->cregs[9] & PER_CR9_EVENT_NULLIFICATION) {
            CPUState *cs = CPU(s390_env_get_cpu(env));

            env->int_pgm_code = PGM_PER;
            env->int_pgm_ilen = get_ilen(cpu_ldub_code(env, addr));

            cs->exception_index = EXCP_PGM;
            cpu_loop_exit(cs);
        }
651 652
    }
}
653
#endif