misc_helper.c 18.7 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"
22
#include "qemu/main-loop.h"
B
Blue Swirl 已提交
23
#include "cpu.h"
24
#include "exec/memory.h"
25
#include "qemu/host-utils.h"
26
#include "exec/helper-proto.h"
27
#include "sysemu/kvm.h"
28
#include "qemu/timer.h"
29
#include "qemu/main-loop.h"
30
#include "exec/address-spaces.h"
31 32 33
#ifdef CONFIG_KVM
#include <linux/kvm.h>
#endif
34
#include "exec/exec-all.h"
P
Paolo Bonzini 已提交
35
#include "exec/cpu_ldst.h"
A
Alexander Graf 已提交
36

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

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

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

59
    cs->exception_index = EXCP_PGM;
60 61 62
    env->int_pgm_code = excp;

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

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

70
    cpu_loop_exit(cs);
71 72
}

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

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

#ifndef CONFIG_USER_ONLY
84

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

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

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

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

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

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

124
#ifndef CONFIG_USER_ONLY
125 126 127
static int modified_clear_reset(S390CPU *cpu)
{
    S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
128
    CPUState *t;
129 130 131

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

144 145 146
static int load_normal_reset(S390CPU *cpu)
{
    S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
147
    CPUState *t;
148 149 150

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

163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
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);
}

191
#define DIAG_308_RC_OK              0x0001
192 193
#define DIAG_308_RC_NO_CONF         0x0102
#define DIAG_308_RC_INVALID         0x0402
194

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

    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) {
212 213
    case 0:
        modified_clear_reset(s390_env_get_cpu(env));
214 215 216
        if (tcg_enabled()) {
            cpu_loop_exit(CPU(s390_env_get_cpu(env)));
        }
217
        break;
218 219
    case 1:
        load_normal_reset(s390_env_get_cpu(env));
220 221 222
        if (tcg_enabled()) {
            cpu_loop_exit(CPU(s390_env_get_cpu(env)));
        }
223
        break;
224 225 226 227 228 229
    case 3:
        s390_reipl_request();
        if (tcg_enabled()) {
            cpu_loop_exit(CPU(s390_env_get_cpu(env)));
        }
        break;
230 231 232 233 234
    case 5:
        if ((r1 & 1) || (addr & 0x0fffULL)) {
            program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
            return;
        }
235 236 237 238 239
        if (!address_space_access_valid(&address_space_memory, addr,
                                        sizeof(IplParameterBlock), false)) {
            program_interrupt(env, PGM_ADDRESSING, ILEN_LATER_INC);
            return;
        }
240
        iplb = g_malloc0(sizeof(IplParameterBlock));
241 242 243 244 245 246 247 248 249 250 251 252 253
        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;
        }

254 255
        s390_ipl_update_diag308(iplb);
        env->regs[r1 + 1] = DIAG_308_RC_OK;
256
out:
257
        g_free(iplb);
258 259 260 261 262 263
        return;
    case 6:
        if ((r1 & 1) || (addr & 0x0fffULL)) {
            program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
            return;
        }
264 265 266 267 268 269 270
        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) {
271
            cpu_physical_memory_write(addr, iplb, be32_to_cpu(iplb->len));
272 273 274 275
            env->regs[r1 + 1] = DIAG_308_RC_OK;
        } else {
            env->regs[r1 + 1] = DIAG_308_RC_NO_CONF;
        }
276 277 278 279 280 281 282 283
        return;
    default:
        hw_error("Unhandled diag308 subcode %" PRIx64, subcode);
        break;
    }
}
#endif

284
void HELPER(diag)(CPUS390XState *env, uint32_t r1, uint32_t r3, uint32_t num)
A
Alexander Graf 已提交
285 286 287 288 289 290
{
    uint64_t r;

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

    if (r) {
310
        program_interrupt(env, PGM_OPERATION, ILEN_LATER_INC);
A
Alexander Graf 已提交
311 312 313 314
    }
}

/* Set Prefix */
315
void HELPER(spx)(CPUS390XState *env, uint64_t a1)
A
Alexander Graf 已提交
316
{
317
    CPUState *cs = CPU(s390_env_get_cpu(env));
318
    uint32_t prefix = a1 & 0x7fffe000;
319

320
    env->psa = prefix;
P
Paolo Bonzini 已提交
321
    HELPER_LOG("prefix: %#x\n", prefix);
322 323
    tlb_flush_page(cs, 0);
    tlb_flush_page(cs, TARGET_PAGE_SIZE);
A
Alexander Graf 已提交
324 325
}

326 327
/* Store Clock */
uint64_t HELPER(stck)(CPUS390XState *env)
A
Alexander Graf 已提交
328 329 330 331
{
    uint64_t time;

    time = env->tod_offset +
332
        time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - env->tod_basetime);
A
Alexander Graf 已提交
333 334 335 336 337

    return time;
}

/* Set Clock Comparator */
338
void HELPER(sckc)(CPUS390XState *env, uint64_t time)
A
Alexander Graf 已提交
339 340 341 342 343
{
    if (time == -1ULL) {
        return;
    }

344 345
    env->ckc = time;

346 347 348
    /* difference between origins */
    time -= env->tod_offset;

A
Alexander Graf 已提交
349
    /* nanoseconds */
350
    time = tod2time(time);
A
Alexander Graf 已提交
351

352
    timer_mod(env->tod_timer, env->tod_basetime + time);
A
Alexander Graf 已提交
353 354 355
}

/* Store Clock Comparator */
356
uint64_t HELPER(stckc)(CPUS390XState *env)
A
Alexander Graf 已提交
357
{
358
    return env->ckc;
A
Alexander Graf 已提交
359 360 361
}

/* Set CPU Timer */
362
void HELPER(spt)(CPUS390XState *env, uint64_t time)
A
Alexander Graf 已提交
363 364 365 366 367 368
{
    if (time == -1ULL) {
        return;
    }

    /* nanoseconds */
369
    time = tod2time(time);
A
Alexander Graf 已提交
370

371 372 373
    env->cputm = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time;

    timer_mod(env->cpu_timer, env->cputm);
A
Alexander Graf 已提交
374 375 376
}

/* Store CPU Timer */
377
uint64_t HELPER(stpt)(CPUS390XState *env)
A
Alexander Graf 已提交
378
{
379
    return time2tod(env->cputm - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
A
Alexander Graf 已提交
380 381 382
}

/* Store System Information */
R
Richard Henderson 已提交
383 384
uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0,
                      uint64_t r0, uint64_t r1)
A
Alexander Graf 已提交
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413
{
    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);
414
            cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
A
Alexander Graf 已提交
415 416 417 418 419 420 421 422 423
        } 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);
424
            cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
A
Alexander Graf 已提交
425 426 427 428 429 430 431 432 433 434 435
        } 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);
436
            cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
A
Alexander Graf 已提交
437 438 439 440 441
        } else {
            cc = 3;
        }
        break;
    case STSI_LEVEL_2:
B
Blue Swirl 已提交
442 443 444 445 446 447 448 449 450 451 452
        {
            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);
453
                cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
B
Blue Swirl 已提交
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
            } 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);
470
                cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
B
Blue Swirl 已提交
471 472 473 474
            } else {
                cc = 3;
            }
            break;
A
Alexander Graf 已提交
475 476
        }
    case STSI_LEVEL_3:
B
Blue Swirl 已提交
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491
        {
            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);
492
                cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
B
Blue Swirl 已提交
493 494 495 496
            } else {
                cc = 3;
            }
            break;
A
Alexander Graf 已提交
497 498 499 500 501 502 503 504 505 506 507 508
        }
    case STSI_LEVEL_CURRENT:
        env->regs[0] = STSI_LEVEL_3;
        break;
    default:
        cc = 3;
        break;
    }

    return cc;
}

509 510
uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1,
                      uint64_t cpu_addr)
A
Alexander Graf 已提交
511
{
512
    int cc = SIGP_CC_ORDER_CODE_ACCEPTED;
A
Alexander Graf 已提交
513 514

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

B
Blue Swirl 已提交
517
    /* Remember: Use "R1 or R1 + 1, whichever is the odd-numbered register"
A
Alexander Graf 已提交
518 519
       as parameter (input). Status (output) is always R1. */

520 521
    /* sigp contains the order code in bit positions 56-63, mask it here. */
    switch (order_code & 0xff) {
A
Alexander Graf 已提交
522 523 524 525 526 527 528 529 530 531 532 533
    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 已提交
534
#if !defined(CONFIG_USER_ONLY)
535 536
    case SIGP_RESTART:
        qemu_system_reset_request();
537
        cpu_loop_exit(CPU(s390_env_get_cpu(env)));
538 539 540
        break;
    case SIGP_STOP:
        qemu_system_shutdown_request();
541
        cpu_loop_exit(CPU(s390_env_get_cpu(env)));
542 543
        break;
#endif
A
Alexander Graf 已提交
544 545 546
    default:
        /* unknown sigp */
        fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code);
547
        cc = SIGP_CC_NOT_OPERATIONAL;
A
Alexander Graf 已提交
548 549 550 551 552
    }

    return cc;
}
#endif
553 554 555 556 557

#ifndef CONFIG_USER_ONLY
void HELPER(xsch)(CPUS390XState *env, uint64_t r1)
{
    S390CPU *cpu = s390_env_get_cpu(env);
558
    qemu_mutex_lock_iothread();
559
    ioinst_handle_xsch(cpu, r1);
560
    qemu_mutex_unlock_iothread();
561 562 563 564 565
}

void HELPER(csch)(CPUS390XState *env, uint64_t r1)
{
    S390CPU *cpu = s390_env_get_cpu(env);
566
    qemu_mutex_lock_iothread();
567
    ioinst_handle_csch(cpu, r1);
568
    qemu_mutex_unlock_iothread();
569 570 571 572 573
}

void HELPER(hsch)(CPUS390XState *env, uint64_t r1)
{
    S390CPU *cpu = s390_env_get_cpu(env);
574
    qemu_mutex_lock_iothread();
575
    ioinst_handle_hsch(cpu, r1);
576
    qemu_mutex_unlock_iothread();
577 578 579 580 581
}

void HELPER(msch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
{
    S390CPU *cpu = s390_env_get_cpu(env);
582
    qemu_mutex_lock_iothread();
583
    ioinst_handle_msch(cpu, r1, inst >> 16);
584
    qemu_mutex_unlock_iothread();
585 586 587 588 589
}

void HELPER(rchp)(CPUS390XState *env, uint64_t r1)
{
    S390CPU *cpu = s390_env_get_cpu(env);
590
    qemu_mutex_lock_iothread();
591
    ioinst_handle_rchp(cpu, r1);
592
    qemu_mutex_unlock_iothread();
593 594 595 596 597
}

void HELPER(rsch)(CPUS390XState *env, uint64_t r1)
{
    S390CPU *cpu = s390_env_get_cpu(env);
598
    qemu_mutex_lock_iothread();
599
    ioinst_handle_rsch(cpu, r1);
600
    qemu_mutex_unlock_iothread();
601 602 603 604 605
}

void HELPER(ssch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
{
    S390CPU *cpu = s390_env_get_cpu(env);
606
    qemu_mutex_lock_iothread();
607
    ioinst_handle_ssch(cpu, r1, inst >> 16);
608
    qemu_mutex_unlock_iothread();
609 610 611 612 613
}

void HELPER(stsch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
{
    S390CPU *cpu = s390_env_get_cpu(env);
614
    qemu_mutex_lock_iothread();
615
    ioinst_handle_stsch(cpu, r1, inst >> 16);
616
    qemu_mutex_unlock_iothread();
617 618 619 620 621
}

void HELPER(tsch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
{
    S390CPU *cpu = s390_env_get_cpu(env);
622
    qemu_mutex_lock_iothread();
623
    ioinst_handle_tsch(cpu, r1, inst >> 16);
624
    qemu_mutex_unlock_iothread();
625 626 627 628 629
}

void HELPER(chsc)(CPUS390XState *env, uint64_t inst)
{
    S390CPU *cpu = s390_env_get_cpu(env);
630
    qemu_mutex_lock_iothread();
631
    ioinst_handle_chsc(cpu, inst >> 16);
632
    qemu_mutex_unlock_iothread();
633 634
}
#endif
635 636 637 638 639 640 641 642 643 644 645 646 647 648

#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);
    }
}
649 650 651 652 653 654 655 656 657 658 659

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);
        }
    }
}
660 661 662 663 664 665

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);
666 667 668 669 670 671 672 673 674 675 676 677

        /* 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);
        }
678 679
    }
}
680
#endif