qemu/target/s390x/sigp.c
<<
>>
Prefs
   1/*
   2 * s390x SIGP instruction handling
   3 *
   4 * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
   5 * Copyright IBM Corp. 2012
   6 *
   7 * This work is licensed under the terms of the GNU GPL, version 2 or later.
   8 * See the COPYING file in the top-level directory.
   9 */
  10
  11#include "qemu/osdep.h"
  12#include "qemu-common.h"
  13#include "cpu.h"
  14#include "internal.h"
  15#include "sysemu/hw_accel.h"
  16#include "exec/address-spaces.h"
  17#include "exec/exec-all.h"
  18#include "sysemu/sysemu.h"
  19#include "trace.h"
  20#include "qapi/qapi-types-misc.h"
  21
  22QemuMutex qemu_sigp_mutex;
  23
  24typedef struct SigpInfo {
  25    uint64_t param;
  26    int cc;
  27    uint64_t *status_reg;
  28} SigpInfo;
  29
  30static void set_sigp_status(SigpInfo *si, uint64_t status)
  31{
  32    *si->status_reg &= 0xffffffff00000000ULL;
  33    *si->status_reg |= status;
  34    si->cc = SIGP_CC_STATUS_STORED;
  35}
  36
  37static void sigp_sense(S390CPU *dst_cpu, SigpInfo *si)
  38{
  39    uint8_t state = s390_cpu_get_state(dst_cpu);
  40    bool ext_call = dst_cpu->env.pending_int & INTERRUPT_EXTERNAL_CALL;
  41    uint64_t status = 0;
  42
  43    if (!tcg_enabled()) {
  44        /* handled in KVM */
  45        set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
  46        return;
  47    }
  48
  49    /* sensing without locks is racy, but it's the same for real hw */
  50    if (state != S390_CPU_STATE_STOPPED && !ext_call) {
  51        si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
  52    } else {
  53        if (ext_call) {
  54            status |= SIGP_STAT_EXT_CALL_PENDING;
  55        }
  56        if (state == S390_CPU_STATE_STOPPED) {
  57            status |= SIGP_STAT_STOPPED;
  58        }
  59        set_sigp_status(si, status);
  60    }
  61}
  62
  63static void sigp_external_call(S390CPU *src_cpu, S390CPU *dst_cpu, SigpInfo *si)
  64{
  65    int ret;
  66
  67    if (!tcg_enabled()) {
  68        /* handled in KVM */
  69        set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
  70        return;
  71    }
  72
  73    ret = cpu_inject_external_call(dst_cpu, src_cpu->env.core_id);
  74    if (!ret) {
  75        si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
  76    } else {
  77        set_sigp_status(si, SIGP_STAT_EXT_CALL_PENDING);
  78    }
  79}
  80
  81static void sigp_emergency(S390CPU *src_cpu, S390CPU *dst_cpu, SigpInfo *si)
  82{
  83    if (!tcg_enabled()) {
  84        /* handled in KVM */
  85        set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
  86        return;
  87    }
  88
  89    cpu_inject_emergency_signal(dst_cpu, src_cpu->env.core_id);
  90    si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
  91}
  92
  93static void sigp_start(CPUState *cs, run_on_cpu_data arg)
  94{
  95    S390CPU *cpu = S390_CPU(cs);
  96    SigpInfo *si = arg.host_ptr;
  97
  98    if (s390_cpu_get_state(cpu) != S390_CPU_STATE_STOPPED) {
  99        si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
 100        return;
 101    }
 102
 103    s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
 104    si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
 105}
 106
 107static void sigp_stop(CPUState *cs, run_on_cpu_data arg)
 108{
 109    S390CPU *cpu = S390_CPU(cs);
 110    SigpInfo *si = arg.host_ptr;
 111
 112    if (s390_cpu_get_state(cpu) != S390_CPU_STATE_OPERATING) {
 113        si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
 114        return;
 115    }
 116
 117    /* disabled wait - sleeping in user space */
 118    if (cs->halted) {
 119        s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu);
 120    } else {
 121        /* execute the stop function */
 122        cpu->env.sigp_order = SIGP_STOP;
 123        cpu_inject_stop(cpu);
 124    }
 125    si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
 126}
 127
 128static void sigp_stop_and_store_status(CPUState *cs, run_on_cpu_data arg)
 129{
 130    S390CPU *cpu = S390_CPU(cs);
 131    SigpInfo *si = arg.host_ptr;
 132
 133    /* disabled wait - sleeping in user space */
 134    if (s390_cpu_get_state(cpu) == S390_CPU_STATE_OPERATING && cs->halted) {
 135        s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu);
 136    }
 137
 138    switch (s390_cpu_get_state(cpu)) {
 139    case S390_CPU_STATE_OPERATING:
 140        cpu->env.sigp_order = SIGP_STOP_STORE_STATUS;
 141        cpu_inject_stop(cpu);
 142        /* store will be performed in do_stop_interrup() */
 143        break;
 144    case S390_CPU_STATE_STOPPED:
 145        /* already stopped, just store the status */
 146        cpu_synchronize_state(cs);
 147        s390_store_status(cpu, S390_STORE_STATUS_DEF_ADDR, true);
 148        break;
 149    }
 150    si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
 151}
 152
 153static void sigp_store_status_at_address(CPUState *cs, run_on_cpu_data arg)
 154{
 155    S390CPU *cpu = S390_CPU(cs);
 156    SigpInfo *si = arg.host_ptr;
 157    uint32_t address = si->param & 0x7ffffe00u;
 158
 159    /* cpu has to be stopped */
 160    if (s390_cpu_get_state(cpu) != S390_CPU_STATE_STOPPED) {
 161        set_sigp_status(si, SIGP_STAT_INCORRECT_STATE);
 162        return;
 163    }
 164
 165    cpu_synchronize_state(cs);
 166
 167    if (s390_store_status(cpu, address, false)) {
 168        set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
 169        return;
 170    }
 171    si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
 172}
 173
 174#define ADTL_SAVE_LC_MASK  0xfUL
 175static void sigp_store_adtl_status(CPUState *cs, run_on_cpu_data arg)
 176{
 177    S390CPU *cpu = S390_CPU(cs);
 178    SigpInfo *si = arg.host_ptr;
 179    uint8_t lc = si->param & ADTL_SAVE_LC_MASK;
 180    hwaddr addr = si->param & ~ADTL_SAVE_LC_MASK;
 181    hwaddr len = 1UL << (lc ? lc : 10);
 182
 183    if (!s390_has_feat(S390_FEAT_VECTOR) &&
 184        !s390_has_feat(S390_FEAT_GUARDED_STORAGE)) {
 185        set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
 186        return;
 187    }
 188
 189    /* cpu has to be stopped */
 190    if (s390_cpu_get_state(cpu) != S390_CPU_STATE_STOPPED) {
 191        set_sigp_status(si, SIGP_STAT_INCORRECT_STATE);
 192        return;
 193    }
 194
 195    /* address must be aligned to length */
 196    if (addr & (len - 1)) {
 197        set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
 198        return;
 199    }
 200
 201    /* no GS: only lc == 0 is valid */
 202    if (!s390_has_feat(S390_FEAT_GUARDED_STORAGE) &&
 203        lc != 0) {
 204        set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
 205        return;
 206    }
 207
 208    /* GS: 0, 10, 11, 12 are valid */
 209    if (s390_has_feat(S390_FEAT_GUARDED_STORAGE) &&
 210        lc != 0 &&
 211        lc != 10 &&
 212        lc != 11 &&
 213        lc != 12) {
 214        set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
 215        return;
 216    }
 217
 218    cpu_synchronize_state(cs);
 219
 220    if (s390_store_adtl_status(cpu, addr, len)) {
 221        set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
 222        return;
 223    }
 224    si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
 225}
 226
 227static void sigp_restart(CPUState *cs, run_on_cpu_data arg)
 228{
 229    S390CPU *cpu = S390_CPU(cs);
 230    SigpInfo *si = arg.host_ptr;
 231
 232    switch (s390_cpu_get_state(cpu)) {
 233    case S390_CPU_STATE_STOPPED:
 234        /* the restart irq has to be delivered prior to any other pending irq */
 235        cpu_synchronize_state(cs);
 236        /*
 237         * Set OPERATING (and unhalting) before loading the restart PSW.
 238         * load_psw() will then properly halt the CPU again if necessary (TCG).
 239         */
 240        s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
 241        do_restart_interrupt(&cpu->env);
 242        break;
 243    case S390_CPU_STATE_OPERATING:
 244        cpu_inject_restart(cpu);
 245        break;
 246    }
 247    si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
 248}
 249
 250static void sigp_initial_cpu_reset(CPUState *cs, run_on_cpu_data arg)
 251{
 252    S390CPU *cpu = S390_CPU(cs);
 253    S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
 254    SigpInfo *si = arg.host_ptr;
 255
 256    cpu_synchronize_state(cs);
 257    scc->initial_cpu_reset(cs);
 258    cpu_synchronize_post_reset(cs);
 259    si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
 260}
 261
 262static void sigp_cpu_reset(CPUState *cs, run_on_cpu_data arg)
 263{
 264    S390CPU *cpu = S390_CPU(cs);
 265    S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
 266    SigpInfo *si = arg.host_ptr;
 267
 268    cpu_synchronize_state(cs);
 269    scc->cpu_reset(cs);
 270    cpu_synchronize_post_reset(cs);
 271    si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
 272}
 273
 274static void sigp_set_prefix(CPUState *cs, run_on_cpu_data arg)
 275{
 276    S390CPU *cpu = S390_CPU(cs);
 277    SigpInfo *si = arg.host_ptr;
 278    uint32_t addr = si->param & 0x7fffe000u;
 279
 280    cpu_synchronize_state(cs);
 281
 282    if (!address_space_access_valid(&address_space_memory, addr,
 283                                    sizeof(struct LowCore), false,
 284                                    MEMTXATTRS_UNSPECIFIED)) {
 285        set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
 286        return;
 287    }
 288
 289    /* cpu has to be stopped */
 290    if (s390_cpu_get_state(cpu) != S390_CPU_STATE_STOPPED) {
 291        set_sigp_status(si, SIGP_STAT_INCORRECT_STATE);
 292        return;
 293    }
 294
 295    cpu->env.psa = addr;
 296    tlb_flush(cs);
 297    cpu_synchronize_post_init(cs);
 298    si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
 299}
 300
 301static void sigp_cond_emergency(S390CPU *src_cpu, S390CPU *dst_cpu,
 302                                SigpInfo *si)
 303{
 304    const uint64_t psw_int_mask = PSW_MASK_IO | PSW_MASK_EXT;
 305    uint16_t p_asn, s_asn, asn;
 306    uint64_t psw_addr, psw_mask;
 307    bool idle;
 308
 309    if (!tcg_enabled()) {
 310        /* handled in KVM */
 311        set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
 312        return;
 313    }
 314
 315    /* this looks racy, but these values are only used when STOPPED */
 316    idle = CPU(dst_cpu)->halted;
 317    psw_addr = dst_cpu->env.psw.addr;
 318    psw_mask = dst_cpu->env.psw.mask;
 319    asn = si->param;
 320    p_asn = dst_cpu->env.cregs[4] & 0xffff;  /* Primary ASN */
 321    s_asn = dst_cpu->env.cregs[3] & 0xffff;  /* Secondary ASN */
 322
 323    if (s390_cpu_get_state(dst_cpu) != S390_CPU_STATE_STOPPED ||
 324        (psw_mask & psw_int_mask) != psw_int_mask ||
 325        (idle && psw_addr != 0) ||
 326        (!idle && (asn == p_asn || asn == s_asn))) {
 327        cpu_inject_emergency_signal(dst_cpu, src_cpu->env.core_id);
 328    } else {
 329        set_sigp_status(si, SIGP_STAT_INCORRECT_STATE);
 330    }
 331
 332    si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
 333}
 334
 335static void sigp_sense_running(S390CPU *dst_cpu, SigpInfo *si)
 336{
 337    if (!tcg_enabled()) {
 338        /* handled in KVM */
 339        set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
 340        return;
 341    }
 342
 343    /* sensing without locks is racy, but it's the same for real hw */
 344    if (!s390_has_feat(S390_FEAT_SENSE_RUNNING_STATUS)) {
 345        set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
 346        return;
 347    }
 348
 349    /* If halted (which includes also STOPPED), it is not running */
 350    if (CPU(dst_cpu)->halted) {
 351        si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
 352    } else {
 353        set_sigp_status(si, SIGP_STAT_NOT_RUNNING);
 354    }
 355}
 356
 357static int handle_sigp_single_dst(S390CPU *cpu, S390CPU *dst_cpu, uint8_t order,
 358                                  uint64_t param, uint64_t *status_reg)
 359{
 360    SigpInfo si = {
 361        .param = param,
 362        .status_reg = status_reg,
 363    };
 364
 365    /* cpu available? */
 366    if (dst_cpu == NULL) {
 367        return SIGP_CC_NOT_OPERATIONAL;
 368    }
 369
 370    /* only resets can break pending orders */
 371    if (dst_cpu->env.sigp_order != 0 &&
 372        order != SIGP_CPU_RESET &&
 373        order != SIGP_INITIAL_CPU_RESET) {
 374        return SIGP_CC_BUSY;
 375    }
 376
 377    switch (order) {
 378    case SIGP_SENSE:
 379        sigp_sense(dst_cpu, &si);
 380        break;
 381    case SIGP_EXTERNAL_CALL:
 382        sigp_external_call(cpu, dst_cpu, &si);
 383        break;
 384    case SIGP_EMERGENCY:
 385        sigp_emergency(cpu, dst_cpu, &si);
 386        break;
 387    case SIGP_START:
 388        run_on_cpu(CPU(dst_cpu), sigp_start, RUN_ON_CPU_HOST_PTR(&si));
 389        break;
 390    case SIGP_STOP:
 391        run_on_cpu(CPU(dst_cpu), sigp_stop, RUN_ON_CPU_HOST_PTR(&si));
 392        break;
 393    case SIGP_RESTART:
 394        run_on_cpu(CPU(dst_cpu), sigp_restart, RUN_ON_CPU_HOST_PTR(&si));
 395        break;
 396    case SIGP_STOP_STORE_STATUS:
 397        run_on_cpu(CPU(dst_cpu), sigp_stop_and_store_status, RUN_ON_CPU_HOST_PTR(&si));
 398        break;
 399    case SIGP_STORE_STATUS_ADDR:
 400        run_on_cpu(CPU(dst_cpu), sigp_store_status_at_address, RUN_ON_CPU_HOST_PTR(&si));
 401        break;
 402    case SIGP_STORE_ADTL_STATUS:
 403        run_on_cpu(CPU(dst_cpu), sigp_store_adtl_status, RUN_ON_CPU_HOST_PTR(&si));
 404        break;
 405    case SIGP_SET_PREFIX:
 406        run_on_cpu(CPU(dst_cpu), sigp_set_prefix, RUN_ON_CPU_HOST_PTR(&si));
 407        break;
 408    case SIGP_INITIAL_CPU_RESET:
 409        run_on_cpu(CPU(dst_cpu), sigp_initial_cpu_reset, RUN_ON_CPU_HOST_PTR(&si));
 410        break;
 411    case SIGP_CPU_RESET:
 412        run_on_cpu(CPU(dst_cpu), sigp_cpu_reset, RUN_ON_CPU_HOST_PTR(&si));
 413        break;
 414    case SIGP_COND_EMERGENCY:
 415        sigp_cond_emergency(cpu, dst_cpu, &si);
 416        break;
 417    case SIGP_SENSE_RUNNING:
 418        sigp_sense_running(dst_cpu, &si);
 419        break;
 420    default:
 421        set_sigp_status(&si, SIGP_STAT_INVALID_ORDER);
 422    }
 423
 424    return si.cc;
 425}
 426
 427static int sigp_set_architecture(S390CPU *cpu, uint32_t param,
 428                                 uint64_t *status_reg)
 429{
 430    CPUState *cur_cs;
 431    S390CPU *cur_cpu;
 432    bool all_stopped = true;
 433
 434    CPU_FOREACH(cur_cs) {
 435        cur_cpu = S390_CPU(cur_cs);
 436
 437        if (cur_cpu == cpu) {
 438            continue;
 439        }
 440        if (s390_cpu_get_state(cur_cpu) != S390_CPU_STATE_STOPPED) {
 441            all_stopped = false;
 442        }
 443    }
 444
 445    *status_reg &= 0xffffffff00000000ULL;
 446
 447    /* Reject set arch order, with czam we're always in z/Arch mode. */
 448    *status_reg |= (all_stopped ? SIGP_STAT_INVALID_PARAMETER :
 449                    SIGP_STAT_INCORRECT_STATE);
 450    return SIGP_CC_STATUS_STORED;
 451}
 452
 453int handle_sigp(CPUS390XState *env, uint8_t order, uint64_t r1, uint64_t r3)
 454{
 455    uint64_t *status_reg = &env->regs[r1];
 456    uint64_t param = (r1 % 2) ? env->regs[r1] : env->regs[r1 + 1];
 457    S390CPU *cpu = s390_env_get_cpu(env);
 458    S390CPU *dst_cpu = NULL;
 459    int ret;
 460
 461    if (qemu_mutex_trylock(&qemu_sigp_mutex)) {
 462        ret = SIGP_CC_BUSY;
 463        goto out;
 464    }
 465
 466    switch (order) {
 467    case SIGP_SET_ARCH:
 468        ret = sigp_set_architecture(cpu, param, status_reg);
 469        break;
 470    default:
 471        /* all other sigp orders target a single vcpu */
 472        dst_cpu = s390_cpu_addr2state(env->regs[r3]);
 473        ret = handle_sigp_single_dst(cpu, dst_cpu, order, param, status_reg);
 474    }
 475    qemu_mutex_unlock(&qemu_sigp_mutex);
 476
 477out:
 478    trace_sigp_finished(order, CPU(cpu)->cpu_index,
 479                        dst_cpu ? CPU(dst_cpu)->cpu_index : -1, ret);
 480    g_assert(ret >= 0);
 481
 482    return ret;
 483}
 484
 485int s390_cpu_restart(S390CPU *cpu)
 486{
 487    SigpInfo si = {};
 488
 489    run_on_cpu(CPU(cpu), sigp_restart, RUN_ON_CPU_HOST_PTR(&si));
 490    return 0;
 491}
 492
 493void do_stop_interrupt(CPUS390XState *env)
 494{
 495    S390CPU *cpu = s390_env_get_cpu(env);
 496
 497    if (s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu) == 0) {
 498        qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
 499    }
 500    if (cpu->env.sigp_order == SIGP_STOP_STORE_STATUS) {
 501        s390_store_status(cpu, S390_STORE_STATUS_DEF_ADDR, true);
 502    }
 503    env->sigp_order = 0;
 504    env->pending_int &= ~INTERRUPT_STOP;
 505}
 506
 507void s390_init_sigp(void)
 508{
 509    qemu_mutex_init(&qemu_sigp_mutex);
 510}
 511