qemu/target-s390x/ioinst.c
<<
>>
Prefs
   1/*
   2 * I/O instructions for S/390
   3 *
   4 * Copyright 2012, 2015 IBM Corp.
   5 * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
   6 *
   7 * This work is licensed under the terms of the GNU GPL, version 2 or (at
   8 * your option) any later version. See the COPYING file in the top-level
   9 * directory.
  10 */
  11
  12#include "qemu/osdep.h"
  13
  14#include "cpu.h"
  15#include "ioinst.h"
  16#include "trace.h"
  17#include "hw/s390x/s390-pci-bus.h"
  18
  19int ioinst_disassemble_sch_ident(uint32_t value, int *m, int *cssid, int *ssid,
  20                                 int *schid)
  21{
  22    if (!IOINST_SCHID_ONE(value)) {
  23        return -EINVAL;
  24    }
  25    if (!IOINST_SCHID_M(value)) {
  26        if (IOINST_SCHID_CSSID(value)) {
  27            return -EINVAL;
  28        }
  29        *cssid = 0;
  30        *m = 0;
  31    } else {
  32        *cssid = IOINST_SCHID_CSSID(value);
  33        *m = 1;
  34    }
  35    *ssid = IOINST_SCHID_SSID(value);
  36    *schid = IOINST_SCHID_NR(value);
  37    return 0;
  38}
  39
  40void ioinst_handle_xsch(S390CPU *cpu, uint64_t reg1)
  41{
  42    int cssid, ssid, schid, m;
  43    SubchDev *sch;
  44    int ret = -ENODEV;
  45    int cc;
  46
  47    if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
  48        program_interrupt(&cpu->env, PGM_OPERAND, 2);
  49        return;
  50    }
  51    trace_ioinst_sch_id("xsch", cssid, ssid, schid);
  52    sch = css_find_subch(m, cssid, ssid, schid);
  53    if (sch && css_subch_visible(sch)) {
  54        ret = css_do_xsch(sch);
  55    }
  56    switch (ret) {
  57    case -ENODEV:
  58        cc = 3;
  59        break;
  60    case -EBUSY:
  61        cc = 2;
  62        break;
  63    case 0:
  64        cc = 0;
  65        break;
  66    default:
  67        cc = 1;
  68        break;
  69    }
  70    setcc(cpu, cc);
  71}
  72
  73void ioinst_handle_csch(S390CPU *cpu, uint64_t reg1)
  74{
  75    int cssid, ssid, schid, m;
  76    SubchDev *sch;
  77    int ret = -ENODEV;
  78    int cc;
  79
  80    if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
  81        program_interrupt(&cpu->env, PGM_OPERAND, 2);
  82        return;
  83    }
  84    trace_ioinst_sch_id("csch", cssid, ssid, schid);
  85    sch = css_find_subch(m, cssid, ssid, schid);
  86    if (sch && css_subch_visible(sch)) {
  87        ret = css_do_csch(sch);
  88    }
  89    if (ret == -ENODEV) {
  90        cc = 3;
  91    } else {
  92        cc = 0;
  93    }
  94    setcc(cpu, cc);
  95}
  96
  97void ioinst_handle_hsch(S390CPU *cpu, uint64_t reg1)
  98{
  99    int cssid, ssid, schid, m;
 100    SubchDev *sch;
 101    int ret = -ENODEV;
 102    int cc;
 103
 104    if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
 105        program_interrupt(&cpu->env, PGM_OPERAND, 2);
 106        return;
 107    }
 108    trace_ioinst_sch_id("hsch", cssid, ssid, schid);
 109    sch = css_find_subch(m, cssid, ssid, schid);
 110    if (sch && css_subch_visible(sch)) {
 111        ret = css_do_hsch(sch);
 112    }
 113    switch (ret) {
 114    case -ENODEV:
 115        cc = 3;
 116        break;
 117    case -EBUSY:
 118        cc = 2;
 119        break;
 120    case 0:
 121        cc = 0;
 122        break;
 123    default:
 124        cc = 1;
 125        break;
 126    }
 127    setcc(cpu, cc);
 128}
 129
 130static int ioinst_schib_valid(SCHIB *schib)
 131{
 132    if ((be16_to_cpu(schib->pmcw.flags) & PMCW_FLAGS_MASK_INVALID) ||
 133        (be32_to_cpu(schib->pmcw.chars) & PMCW_CHARS_MASK_INVALID)) {
 134        return 0;
 135    }
 136    /* Disallow extended measurements for now. */
 137    if (be32_to_cpu(schib->pmcw.chars) & PMCW_CHARS_MASK_XMWME) {
 138        return 0;
 139    }
 140    return 1;
 141}
 142
 143void ioinst_handle_msch(S390CPU *cpu, uint64_t reg1, uint32_t ipb)
 144{
 145    int cssid, ssid, schid, m;
 146    SubchDev *sch;
 147    SCHIB schib;
 148    uint64_t addr;
 149    int ret = -ENODEV;
 150    int cc;
 151    CPUS390XState *env = &cpu->env;
 152    uint8_t ar;
 153
 154    addr = decode_basedisp_s(env, ipb, &ar);
 155    if (addr & 3) {
 156        program_interrupt(env, PGM_SPECIFICATION, 2);
 157        return;
 158    }
 159    if (s390_cpu_virt_mem_read(cpu, addr, ar, &schib, sizeof(schib))) {
 160        return;
 161    }
 162    if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid) ||
 163        !ioinst_schib_valid(&schib)) {
 164        program_interrupt(env, PGM_OPERAND, 2);
 165        return;
 166    }
 167    trace_ioinst_sch_id("msch", cssid, ssid, schid);
 168    sch = css_find_subch(m, cssid, ssid, schid);
 169    if (sch && css_subch_visible(sch)) {
 170        ret = css_do_msch(sch, &schib);
 171    }
 172    switch (ret) {
 173    case -ENODEV:
 174        cc = 3;
 175        break;
 176    case -EBUSY:
 177        cc = 2;
 178        break;
 179    case 0:
 180        cc = 0;
 181        break;
 182    default:
 183        cc = 1;
 184        break;
 185    }
 186    setcc(cpu, cc);
 187}
 188
 189static void copy_orb_from_guest(ORB *dest, const ORB *src)
 190{
 191    dest->intparm = be32_to_cpu(src->intparm);
 192    dest->ctrl0 = be16_to_cpu(src->ctrl0);
 193    dest->lpm = src->lpm;
 194    dest->ctrl1 = src->ctrl1;
 195    dest->cpa = be32_to_cpu(src->cpa);
 196}
 197
 198static int ioinst_orb_valid(ORB *orb)
 199{
 200    if ((orb->ctrl0 & ORB_CTRL0_MASK_INVALID) ||
 201        (orb->ctrl1 & ORB_CTRL1_MASK_INVALID)) {
 202        return 0;
 203    }
 204    if ((orb->cpa & HIGH_ORDER_BIT) != 0) {
 205        return 0;
 206    }
 207    return 1;
 208}
 209
 210void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb)
 211{
 212    int cssid, ssid, schid, m;
 213    SubchDev *sch;
 214    ORB orig_orb, orb;
 215    uint64_t addr;
 216    int ret = -ENODEV;
 217    int cc;
 218    CPUS390XState *env = &cpu->env;
 219    uint8_t ar;
 220
 221    addr = decode_basedisp_s(env, ipb, &ar);
 222    if (addr & 3) {
 223        program_interrupt(env, PGM_SPECIFICATION, 2);
 224        return;
 225    }
 226    if (s390_cpu_virt_mem_read(cpu, addr, ar, &orig_orb, sizeof(orb))) {
 227        return;
 228    }
 229    copy_orb_from_guest(&orb, &orig_orb);
 230    if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid) ||
 231        !ioinst_orb_valid(&orb)) {
 232        program_interrupt(env, PGM_OPERAND, 2);
 233        return;
 234    }
 235    trace_ioinst_sch_id("ssch", cssid, ssid, schid);
 236    sch = css_find_subch(m, cssid, ssid, schid);
 237    if (sch && css_subch_visible(sch)) {
 238        ret = css_do_ssch(sch, &orb);
 239    }
 240    switch (ret) {
 241    case -ENODEV:
 242        cc = 3;
 243        break;
 244    case -EBUSY:
 245        cc = 2;
 246        break;
 247    case 0:
 248        cc = 0;
 249        break;
 250    default:
 251        cc = 1;
 252        break;
 253    }
 254    setcc(cpu, cc);
 255}
 256
 257void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb)
 258{
 259    CRW crw;
 260    uint64_t addr;
 261    int cc;
 262    CPUS390XState *env = &cpu->env;
 263    uint8_t ar;
 264
 265    addr = decode_basedisp_s(env, ipb, &ar);
 266    if (addr & 3) {
 267        program_interrupt(env, PGM_SPECIFICATION, 2);
 268        return;
 269    }
 270
 271    cc = css_do_stcrw(&crw);
 272    /* 0 - crw stored, 1 - zeroes stored */
 273
 274    if (s390_cpu_virt_mem_write(cpu, addr, ar, &crw, sizeof(crw)) == 0) {
 275        setcc(cpu, cc);
 276    } else if (cc == 0) {
 277        /* Write failed: requeue CRW since STCRW is a suppressing instruction */
 278        css_undo_stcrw(&crw);
 279    }
 280}
 281
 282void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb)
 283{
 284    int cssid, ssid, schid, m;
 285    SubchDev *sch;
 286    uint64_t addr;
 287    int cc;
 288    SCHIB schib;
 289    CPUS390XState *env = &cpu->env;
 290    uint8_t ar;
 291
 292    addr = decode_basedisp_s(env, ipb, &ar);
 293    if (addr & 3) {
 294        program_interrupt(env, PGM_SPECIFICATION, 2);
 295        return;
 296    }
 297
 298    if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
 299        /*
 300         * As operand exceptions have a lower priority than access exceptions,
 301         * we check whether the memory area is writeable (injecting the
 302         * access execption if it is not) first.
 303         */
 304        if (!s390_cpu_virt_mem_check_write(cpu, addr, ar, sizeof(schib))) {
 305            program_interrupt(env, PGM_OPERAND, 2);
 306        }
 307        return;
 308    }
 309    trace_ioinst_sch_id("stsch", cssid, ssid, schid);
 310    sch = css_find_subch(m, cssid, ssid, schid);
 311    if (sch) {
 312        if (css_subch_visible(sch)) {
 313            css_do_stsch(sch, &schib);
 314            cc = 0;
 315        } else {
 316            /* Indicate no more subchannels in this css/ss */
 317            cc = 3;
 318        }
 319    } else {
 320        if (css_schid_final(m, cssid, ssid, schid)) {
 321            cc = 3; /* No more subchannels in this css/ss */
 322        } else {
 323            /* Store an empty schib. */
 324            memset(&schib, 0, sizeof(schib));
 325            cc = 0;
 326        }
 327    }
 328    if (cc != 3) {
 329        if (s390_cpu_virt_mem_write(cpu, addr, ar, &schib,
 330                                    sizeof(schib)) != 0) {
 331            return;
 332        }
 333    } else {
 334        /* Access exceptions have a higher priority than cc3 */
 335        if (s390_cpu_virt_mem_check_write(cpu, addr, ar, sizeof(schib)) != 0) {
 336            return;
 337        }
 338    }
 339    setcc(cpu, cc);
 340}
 341
 342int ioinst_handle_tsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb)
 343{
 344    CPUS390XState *env = &cpu->env;
 345    int cssid, ssid, schid, m;
 346    SubchDev *sch;
 347    IRB irb;
 348    uint64_t addr;
 349    int cc, irb_len;
 350    uint8_t ar;
 351
 352    if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
 353        program_interrupt(env, PGM_OPERAND, 2);
 354        return -EIO;
 355    }
 356    trace_ioinst_sch_id("tsch", cssid, ssid, schid);
 357    addr = decode_basedisp_s(env, ipb, &ar);
 358    if (addr & 3) {
 359        program_interrupt(env, PGM_SPECIFICATION, 2);
 360        return -EIO;
 361    }
 362
 363    sch = css_find_subch(m, cssid, ssid, schid);
 364    if (sch && css_subch_visible(sch)) {
 365        cc = css_do_tsch_get_irb(sch, &irb, &irb_len);
 366    } else {
 367        cc = 3;
 368    }
 369    /* 0 - status pending, 1 - not status pending, 3 - not operational */
 370    if (cc != 3) {
 371        if (s390_cpu_virt_mem_write(cpu, addr, ar, &irb, irb_len) != 0) {
 372            return -EFAULT;
 373        }
 374        css_do_tsch_update_subch(sch);
 375    } else {
 376        irb_len = sizeof(irb) - sizeof(irb.emw);
 377        /* Access exceptions have a higher priority than cc3 */
 378        if (s390_cpu_virt_mem_check_write(cpu, addr, ar, irb_len) != 0) {
 379            return -EFAULT;
 380        }
 381    }
 382
 383    setcc(cpu, cc);
 384    return 0;
 385}
 386
 387typedef struct ChscReq {
 388    uint16_t len;
 389    uint16_t command;
 390    uint32_t param0;
 391    uint32_t param1;
 392    uint32_t param2;
 393} QEMU_PACKED ChscReq;
 394
 395typedef struct ChscResp {
 396    uint16_t len;
 397    uint16_t code;
 398    uint32_t param;
 399    char data[0];
 400} QEMU_PACKED ChscResp;
 401
 402#define CHSC_MIN_RESP_LEN 0x0008
 403
 404#define CHSC_SCPD 0x0002
 405#define CHSC_SCSC 0x0010
 406#define CHSC_SDA  0x0031
 407#define CHSC_SEI  0x000e
 408
 409#define CHSC_SCPD_0_M 0x20000000
 410#define CHSC_SCPD_0_C 0x10000000
 411#define CHSC_SCPD_0_FMT 0x0f000000
 412#define CHSC_SCPD_0_CSSID 0x00ff0000
 413#define CHSC_SCPD_0_RFMT 0x00000f00
 414#define CHSC_SCPD_0_RES 0xc000f000
 415#define CHSC_SCPD_1_RES 0xffffff00
 416#define CHSC_SCPD_01_CHPID 0x000000ff
 417static void ioinst_handle_chsc_scpd(ChscReq *req, ChscResp *res)
 418{
 419    uint16_t len = be16_to_cpu(req->len);
 420    uint32_t param0 = be32_to_cpu(req->param0);
 421    uint32_t param1 = be32_to_cpu(req->param1);
 422    uint16_t resp_code;
 423    int rfmt;
 424    uint16_t cssid;
 425    uint8_t f_chpid, l_chpid;
 426    int desc_size;
 427    int m;
 428
 429    rfmt = (param0 & CHSC_SCPD_0_RFMT) >> 8;
 430    if ((rfmt == 0) ||  (rfmt == 1)) {
 431        rfmt = !!(param0 & CHSC_SCPD_0_C);
 432    }
 433    if ((len != 0x0010) || (param0 & CHSC_SCPD_0_RES) ||
 434        (param1 & CHSC_SCPD_1_RES) || req->param2) {
 435        resp_code = 0x0003;
 436        goto out_err;
 437    }
 438    if (param0 & CHSC_SCPD_0_FMT) {
 439        resp_code = 0x0007;
 440        goto out_err;
 441    }
 442    cssid = (param0 & CHSC_SCPD_0_CSSID) >> 16;
 443    m = param0 & CHSC_SCPD_0_M;
 444    if (cssid != 0) {
 445        if (!m || !css_present(cssid)) {
 446            resp_code = 0x0008;
 447            goto out_err;
 448        }
 449    }
 450    f_chpid = param0 & CHSC_SCPD_01_CHPID;
 451    l_chpid = param1 & CHSC_SCPD_01_CHPID;
 452    if (l_chpid < f_chpid) {
 453        resp_code = 0x0003;
 454        goto out_err;
 455    }
 456    /* css_collect_chp_desc() is endian-aware */
 457    desc_size = css_collect_chp_desc(m, cssid, f_chpid, l_chpid, rfmt,
 458                                     &res->data);
 459    res->code = cpu_to_be16(0x0001);
 460    res->len = cpu_to_be16(8 + desc_size);
 461    res->param = cpu_to_be32(rfmt);
 462    return;
 463
 464  out_err:
 465    res->code = cpu_to_be16(resp_code);
 466    res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
 467    res->param = cpu_to_be32(rfmt);
 468}
 469
 470#define CHSC_SCSC_0_M 0x20000000
 471#define CHSC_SCSC_0_FMT 0x000f0000
 472#define CHSC_SCSC_0_CSSID 0x0000ff00
 473#define CHSC_SCSC_0_RES 0xdff000ff
 474static void ioinst_handle_chsc_scsc(ChscReq *req, ChscResp *res)
 475{
 476    uint16_t len = be16_to_cpu(req->len);
 477    uint32_t param0 = be32_to_cpu(req->param0);
 478    uint8_t cssid;
 479    uint16_t resp_code;
 480    uint32_t general_chars[510];
 481    uint32_t chsc_chars[508];
 482
 483    if (len != 0x0010) {
 484        resp_code = 0x0003;
 485        goto out_err;
 486    }
 487
 488    if (param0 & CHSC_SCSC_0_FMT) {
 489        resp_code = 0x0007;
 490        goto out_err;
 491    }
 492    cssid = (param0 & CHSC_SCSC_0_CSSID) >> 8;
 493    if (cssid != 0) {
 494        if (!(param0 & CHSC_SCSC_0_M) || !css_present(cssid)) {
 495            resp_code = 0x0008;
 496            goto out_err;
 497        }
 498    }
 499    if ((param0 & CHSC_SCSC_0_RES) || req->param1 || req->param2) {
 500        resp_code = 0x0003;
 501        goto out_err;
 502    }
 503    res->code = cpu_to_be16(0x0001);
 504    res->len = cpu_to_be16(4080);
 505    res->param = 0;
 506
 507    memset(general_chars, 0, sizeof(general_chars));
 508    memset(chsc_chars, 0, sizeof(chsc_chars));
 509
 510    general_chars[0] = cpu_to_be32(0x03000000);
 511    general_chars[1] = cpu_to_be32(0x00059000);
 512
 513    chsc_chars[0] = cpu_to_be32(0x40000000);
 514    chsc_chars[3] = cpu_to_be32(0x00040000);
 515
 516    memcpy(res->data, general_chars, sizeof(general_chars));
 517    memcpy(res->data + sizeof(general_chars), chsc_chars, sizeof(chsc_chars));
 518    return;
 519
 520  out_err:
 521    res->code = cpu_to_be16(resp_code);
 522    res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
 523    res->param = 0;
 524}
 525
 526#define CHSC_SDA_0_FMT 0x0f000000
 527#define CHSC_SDA_0_OC 0x0000ffff
 528#define CHSC_SDA_0_RES 0xf0ff0000
 529#define CHSC_SDA_OC_MCSSE 0x0
 530#define CHSC_SDA_OC_MSS 0x2
 531static void ioinst_handle_chsc_sda(ChscReq *req, ChscResp *res)
 532{
 533    uint16_t resp_code = 0x0001;
 534    uint16_t len = be16_to_cpu(req->len);
 535    uint32_t param0 = be32_to_cpu(req->param0);
 536    uint16_t oc;
 537    int ret;
 538
 539    if ((len != 0x0400) || (param0 & CHSC_SDA_0_RES)) {
 540        resp_code = 0x0003;
 541        goto out;
 542    }
 543
 544    if (param0 & CHSC_SDA_0_FMT) {
 545        resp_code = 0x0007;
 546        goto out;
 547    }
 548
 549    oc = param0 & CHSC_SDA_0_OC;
 550    switch (oc) {
 551    case CHSC_SDA_OC_MCSSE:
 552        ret = css_enable_mcsse();
 553        if (ret == -EINVAL) {
 554            resp_code = 0x0101;
 555            goto out;
 556        }
 557        break;
 558    case CHSC_SDA_OC_MSS:
 559        ret = css_enable_mss();
 560        if (ret == -EINVAL) {
 561            resp_code = 0x0101;
 562            goto out;
 563        }
 564        break;
 565    default:
 566        resp_code = 0x0003;
 567        goto out;
 568    }
 569
 570out:
 571    res->code = cpu_to_be16(resp_code);
 572    res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
 573    res->param = 0;
 574}
 575
 576static int chsc_sei_nt0_get_event(void *res)
 577{
 578    /* no events yet */
 579    return 1;
 580}
 581
 582static int chsc_sei_nt0_have_event(void)
 583{
 584    /* no events yet */
 585    return 0;
 586}
 587
 588#define CHSC_SEI_NT0    (1ULL << 63)
 589#define CHSC_SEI_NT2    (1ULL << 61)
 590static void ioinst_handle_chsc_sei(ChscReq *req, ChscResp *res)
 591{
 592    uint64_t selection_mask = ldq_p(&req->param1);
 593    uint8_t *res_flags = (uint8_t *)res->data;
 594    int have_event = 0;
 595    int have_more = 0;
 596
 597    /* regarding architecture nt0 can not be masked */
 598    have_event = !chsc_sei_nt0_get_event(res);
 599    have_more = chsc_sei_nt0_have_event();
 600
 601    if (selection_mask & CHSC_SEI_NT2) {
 602        if (!have_event) {
 603            have_event = !chsc_sei_nt2_get_event(res);
 604        }
 605
 606        if (!have_more) {
 607            have_more = chsc_sei_nt2_have_event();
 608        }
 609    }
 610
 611    if (have_event) {
 612        res->code = cpu_to_be16(0x0001);
 613        if (have_more) {
 614            (*res_flags) |= 0x80;
 615        } else {
 616            (*res_flags) &= ~0x80;
 617            css_clear_sei_pending();
 618        }
 619    } else {
 620        res->code = cpu_to_be16(0x0005);
 621        res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
 622    }
 623}
 624
 625static void ioinst_handle_chsc_unimplemented(ChscResp *res)
 626{
 627    res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
 628    res->code = cpu_to_be16(0x0004);
 629    res->param = 0;
 630}
 631
 632void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb)
 633{
 634    ChscReq *req;
 635    ChscResp *res;
 636    uint64_t addr;
 637    int reg;
 638    uint16_t len;
 639    uint16_t command;
 640    CPUS390XState *env = &cpu->env;
 641    uint8_t buf[TARGET_PAGE_SIZE];
 642
 643    trace_ioinst("chsc");
 644    reg = (ipb >> 20) & 0x00f;
 645    addr = env->regs[reg];
 646    /* Page boundary? */
 647    if (addr & 0xfff) {
 648        program_interrupt(env, PGM_SPECIFICATION, 2);
 649        return;
 650    }
 651    /*
 652     * Reading sizeof(ChscReq) bytes is currently enough for all of our
 653     * present CHSC sub-handlers ... if we ever need more, we should take
 654     * care of req->len here first.
 655     */
 656    if (s390_cpu_virt_mem_read(cpu, addr, reg, buf, sizeof(ChscReq))) {
 657        return;
 658    }
 659    req = (ChscReq *)buf;
 660    len = be16_to_cpu(req->len);
 661    /* Length field valid? */
 662    if ((len < 16) || (len > 4088) || (len & 7)) {
 663        program_interrupt(env, PGM_OPERAND, 2);
 664        return;
 665    }
 666    memset((char *)req + len, 0, TARGET_PAGE_SIZE - len);
 667    res = (void *)((char *)req + len);
 668    command = be16_to_cpu(req->command);
 669    trace_ioinst_chsc_cmd(command, len);
 670    switch (command) {
 671    case CHSC_SCSC:
 672        ioinst_handle_chsc_scsc(req, res);
 673        break;
 674    case CHSC_SCPD:
 675        ioinst_handle_chsc_scpd(req, res);
 676        break;
 677    case CHSC_SDA:
 678        ioinst_handle_chsc_sda(req, res);
 679        break;
 680    case CHSC_SEI:
 681        ioinst_handle_chsc_sei(req, res);
 682        break;
 683    default:
 684        ioinst_handle_chsc_unimplemented(res);
 685        break;
 686    }
 687
 688    if (!s390_cpu_virt_mem_write(cpu, addr + len, reg, res,
 689                                 be16_to_cpu(res->len))) {
 690        setcc(cpu, 0);    /* Command execution complete */
 691    }
 692}
 693
 694int ioinst_handle_tpi(S390CPU *cpu, uint32_t ipb)
 695{
 696    CPUS390XState *env = &cpu->env;
 697    uint64_t addr;
 698    int lowcore;
 699    IOIntCode int_code;
 700    hwaddr len;
 701    int ret;
 702    uint8_t ar;
 703
 704    trace_ioinst("tpi");
 705    addr = decode_basedisp_s(env, ipb, &ar);
 706    if (addr & 3) {
 707        program_interrupt(env, PGM_SPECIFICATION, 2);
 708        return -EIO;
 709    }
 710
 711    lowcore = addr ? 0 : 1;
 712    len = lowcore ? 8 /* two words */ : 12 /* three words */;
 713    ret = css_do_tpi(&int_code, lowcore);
 714    if (ret == 1) {
 715        s390_cpu_virt_mem_write(cpu, lowcore ? 184 : addr, ar, &int_code, len);
 716    }
 717    return ret;
 718}
 719
 720#define SCHM_REG1_RES(_reg) (_reg & 0x000000000ffffffc)
 721#define SCHM_REG1_MBK(_reg) ((_reg & 0x00000000f0000000) >> 28)
 722#define SCHM_REG1_UPD(_reg) ((_reg & 0x0000000000000002) >> 1)
 723#define SCHM_REG1_DCT(_reg) (_reg & 0x0000000000000001)
 724
 725void ioinst_handle_schm(S390CPU *cpu, uint64_t reg1, uint64_t reg2,
 726                        uint32_t ipb)
 727{
 728    uint8_t mbk;
 729    int update;
 730    int dct;
 731    CPUS390XState *env = &cpu->env;
 732
 733    trace_ioinst("schm");
 734
 735    if (SCHM_REG1_RES(reg1)) {
 736        program_interrupt(env, PGM_OPERAND, 2);
 737        return;
 738    }
 739
 740    mbk = SCHM_REG1_MBK(reg1);
 741    update = SCHM_REG1_UPD(reg1);
 742    dct = SCHM_REG1_DCT(reg1);
 743
 744    if (update && (reg2 & 0x000000000000001f)) {
 745        program_interrupt(env, PGM_OPERAND, 2);
 746        return;
 747    }
 748
 749    css_do_schm(mbk, update, dct, update ? reg2 : 0);
 750}
 751
 752void ioinst_handle_rsch(S390CPU *cpu, uint64_t reg1)
 753{
 754    int cssid, ssid, schid, m;
 755    SubchDev *sch;
 756    int ret = -ENODEV;
 757    int cc;
 758
 759    if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
 760        program_interrupt(&cpu->env, PGM_OPERAND, 2);
 761        return;
 762    }
 763    trace_ioinst_sch_id("rsch", cssid, ssid, schid);
 764    sch = css_find_subch(m, cssid, ssid, schid);
 765    if (sch && css_subch_visible(sch)) {
 766        ret = css_do_rsch(sch);
 767    }
 768    switch (ret) {
 769    case -ENODEV:
 770        cc = 3;
 771        break;
 772    case -EINVAL:
 773        cc = 2;
 774        break;
 775    case 0:
 776        cc = 0;
 777        break;
 778    default:
 779        cc = 1;
 780        break;
 781    }
 782    setcc(cpu, cc);
 783}
 784
 785#define RCHP_REG1_RES(_reg) (_reg & 0x00000000ff00ff00)
 786#define RCHP_REG1_CSSID(_reg) ((_reg & 0x0000000000ff0000) >> 16)
 787#define RCHP_REG1_CHPID(_reg) (_reg & 0x00000000000000ff)
 788void ioinst_handle_rchp(S390CPU *cpu, uint64_t reg1)
 789{
 790    int cc;
 791    uint8_t cssid;
 792    uint8_t chpid;
 793    int ret;
 794    CPUS390XState *env = &cpu->env;
 795
 796    if (RCHP_REG1_RES(reg1)) {
 797        program_interrupt(env, PGM_OPERAND, 2);
 798        return;
 799    }
 800
 801    cssid = RCHP_REG1_CSSID(reg1);
 802    chpid = RCHP_REG1_CHPID(reg1);
 803
 804    trace_ioinst_chp_id("rchp", cssid, chpid);
 805
 806    ret = css_do_rchp(cssid, chpid);
 807
 808    switch (ret) {
 809    case -ENODEV:
 810        cc = 3;
 811        break;
 812    case -EBUSY:
 813        cc = 2;
 814        break;
 815    case 0:
 816        cc = 0;
 817        break;
 818    default:
 819        /* Invalid channel subsystem. */
 820        program_interrupt(env, PGM_OPERAND, 2);
 821        return;
 822    }
 823    setcc(cpu, cc);
 824}
 825
 826#define SAL_REG1_INVALID(_reg) (_reg & 0x0000000080000000)
 827void ioinst_handle_sal(S390CPU *cpu, uint64_t reg1)
 828{
 829    /* We do not provide address limit checking, so let's suppress it. */
 830    if (SAL_REG1_INVALID(reg1) || reg1 & 0x000000000000ffff) {
 831        program_interrupt(&cpu->env, PGM_OPERAND, 2);
 832    }
 833}
 834