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 "hw/s390x/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    general_chars[3] = cpu_to_be32(0x00080000);
 513
 514    chsc_chars[0] = cpu_to_be32(0x40000000);
 515    chsc_chars[3] = cpu_to_be32(0x00040000);
 516
 517    memcpy(res->data, general_chars, sizeof(general_chars));
 518    memcpy(res->data + sizeof(general_chars), chsc_chars, sizeof(chsc_chars));
 519    return;
 520
 521  out_err:
 522    res->code = cpu_to_be16(resp_code);
 523    res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
 524    res->param = 0;
 525}
 526
 527#define CHSC_SDA_0_FMT 0x0f000000
 528#define CHSC_SDA_0_OC 0x0000ffff
 529#define CHSC_SDA_0_RES 0xf0ff0000
 530#define CHSC_SDA_OC_MCSSE 0x0
 531#define CHSC_SDA_OC_MSS 0x2
 532static void ioinst_handle_chsc_sda(ChscReq *req, ChscResp *res)
 533{
 534    uint16_t resp_code = 0x0001;
 535    uint16_t len = be16_to_cpu(req->len);
 536    uint32_t param0 = be32_to_cpu(req->param0);
 537    uint16_t oc;
 538    int ret;
 539
 540    if ((len != 0x0400) || (param0 & CHSC_SDA_0_RES)) {
 541        resp_code = 0x0003;
 542        goto out;
 543    }
 544
 545    if (param0 & CHSC_SDA_0_FMT) {
 546        resp_code = 0x0007;
 547        goto out;
 548    }
 549
 550    oc = param0 & CHSC_SDA_0_OC;
 551    switch (oc) {
 552    case CHSC_SDA_OC_MCSSE:
 553        ret = css_enable_mcsse();
 554        if (ret == -EINVAL) {
 555            resp_code = 0x0101;
 556            goto out;
 557        }
 558        break;
 559    case CHSC_SDA_OC_MSS:
 560        ret = css_enable_mss();
 561        if (ret == -EINVAL) {
 562            resp_code = 0x0101;
 563            goto out;
 564        }
 565        break;
 566    default:
 567        resp_code = 0x0003;
 568        goto out;
 569    }
 570
 571out:
 572    res->code = cpu_to_be16(resp_code);
 573    res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
 574    res->param = 0;
 575}
 576
 577static int chsc_sei_nt0_get_event(void *res)
 578{
 579    /* no events yet */
 580    return 1;
 581}
 582
 583static int chsc_sei_nt0_have_event(void)
 584{
 585    /* no events yet */
 586    return 0;
 587}
 588
 589#define CHSC_SEI_NT0    (1ULL << 63)
 590#define CHSC_SEI_NT2    (1ULL << 61)
 591static void ioinst_handle_chsc_sei(ChscReq *req, ChscResp *res)
 592{
 593    uint64_t selection_mask = ldq_p(&req->param1);
 594    uint8_t *res_flags = (uint8_t *)res->data;
 595    int have_event = 0;
 596    int have_more = 0;
 597
 598    /* regarding architecture nt0 can not be masked */
 599    have_event = !chsc_sei_nt0_get_event(res);
 600    have_more = chsc_sei_nt0_have_event();
 601
 602    if (selection_mask & CHSC_SEI_NT2) {
 603        if (!have_event) {
 604            have_event = !chsc_sei_nt2_get_event(res);
 605        }
 606
 607        if (!have_more) {
 608            have_more = chsc_sei_nt2_have_event();
 609        }
 610    }
 611
 612    if (have_event) {
 613        res->code = cpu_to_be16(0x0001);
 614        if (have_more) {
 615            (*res_flags) |= 0x80;
 616        } else {
 617            (*res_flags) &= ~0x80;
 618            css_clear_sei_pending();
 619        }
 620    } else {
 621        res->code = cpu_to_be16(0x0005);
 622        res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
 623    }
 624}
 625
 626static void ioinst_handle_chsc_unimplemented(ChscResp *res)
 627{
 628    res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
 629    res->code = cpu_to_be16(0x0004);
 630    res->param = 0;
 631}
 632
 633void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb)
 634{
 635    ChscReq *req;
 636    ChscResp *res;
 637    uint64_t addr;
 638    int reg;
 639    uint16_t len;
 640    uint16_t command;
 641    CPUS390XState *env = &cpu->env;
 642    uint8_t buf[TARGET_PAGE_SIZE];
 643
 644    trace_ioinst("chsc");
 645    reg = (ipb >> 20) & 0x00f;
 646    addr = env->regs[reg];
 647    /* Page boundary? */
 648    if (addr & 0xfff) {
 649        program_interrupt(env, PGM_SPECIFICATION, 2);
 650        return;
 651    }
 652    /*
 653     * Reading sizeof(ChscReq) bytes is currently enough for all of our
 654     * present CHSC sub-handlers ... if we ever need more, we should take
 655     * care of req->len here first.
 656     */
 657    if (s390_cpu_virt_mem_read(cpu, addr, reg, buf, sizeof(ChscReq))) {
 658        return;
 659    }
 660    req = (ChscReq *)buf;
 661    len = be16_to_cpu(req->len);
 662    /* Length field valid? */
 663    if ((len < 16) || (len > 4088) || (len & 7)) {
 664        program_interrupt(env, PGM_OPERAND, 2);
 665        return;
 666    }
 667    memset((char *)req + len, 0, TARGET_PAGE_SIZE - len);
 668    res = (void *)((char *)req + len);
 669    command = be16_to_cpu(req->command);
 670    trace_ioinst_chsc_cmd(command, len);
 671    switch (command) {
 672    case CHSC_SCSC:
 673        ioinst_handle_chsc_scsc(req, res);
 674        break;
 675    case CHSC_SCPD:
 676        ioinst_handle_chsc_scpd(req, res);
 677        break;
 678    case CHSC_SDA:
 679        ioinst_handle_chsc_sda(req, res);
 680        break;
 681    case CHSC_SEI:
 682        ioinst_handle_chsc_sei(req, res);
 683        break;
 684    default:
 685        ioinst_handle_chsc_unimplemented(res);
 686        break;
 687    }
 688
 689    if (!s390_cpu_virt_mem_write(cpu, addr + len, reg, res,
 690                                 be16_to_cpu(res->len))) {
 691        setcc(cpu, 0);    /* Command execution complete */
 692    }
 693}
 694
 695int ioinst_handle_tpi(S390CPU *cpu, uint32_t ipb)
 696{
 697    CPUS390XState *env = &cpu->env;
 698    uint64_t addr;
 699    int lowcore;
 700    IOIntCode int_code;
 701    hwaddr len;
 702    int ret;
 703    uint8_t ar;
 704
 705    trace_ioinst("tpi");
 706    addr = decode_basedisp_s(env, ipb, &ar);
 707    if (addr & 3) {
 708        program_interrupt(env, PGM_SPECIFICATION, 2);
 709        return -EIO;
 710    }
 711
 712    lowcore = addr ? 0 : 1;
 713    len = lowcore ? 8 /* two words */ : 12 /* three words */;
 714    ret = css_do_tpi(&int_code, lowcore);
 715    if (ret == 1) {
 716        s390_cpu_virt_mem_write(cpu, lowcore ? 184 : addr, ar, &int_code, len);
 717    }
 718    return ret;
 719}
 720
 721#define SCHM_REG1_RES(_reg) (_reg & 0x000000000ffffffc)
 722#define SCHM_REG1_MBK(_reg) ((_reg & 0x00000000f0000000) >> 28)
 723#define SCHM_REG1_UPD(_reg) ((_reg & 0x0000000000000002) >> 1)
 724#define SCHM_REG1_DCT(_reg) (_reg & 0x0000000000000001)
 725
 726void ioinst_handle_schm(S390CPU *cpu, uint64_t reg1, uint64_t reg2,
 727                        uint32_t ipb)
 728{
 729    uint8_t mbk;
 730    int update;
 731    int dct;
 732    CPUS390XState *env = &cpu->env;
 733
 734    trace_ioinst("schm");
 735
 736    if (SCHM_REG1_RES(reg1)) {
 737        program_interrupt(env, PGM_OPERAND, 2);
 738        return;
 739    }
 740
 741    mbk = SCHM_REG1_MBK(reg1);
 742    update = SCHM_REG1_UPD(reg1);
 743    dct = SCHM_REG1_DCT(reg1);
 744
 745    if (update && (reg2 & 0x000000000000001f)) {
 746        program_interrupt(env, PGM_OPERAND, 2);
 747        return;
 748    }
 749
 750    css_do_schm(mbk, update, dct, update ? reg2 : 0);
 751}
 752
 753void ioinst_handle_rsch(S390CPU *cpu, uint64_t reg1)
 754{
 755    int cssid, ssid, schid, m;
 756    SubchDev *sch;
 757    int ret = -ENODEV;
 758    int cc;
 759
 760    if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
 761        program_interrupt(&cpu->env, PGM_OPERAND, 2);
 762        return;
 763    }
 764    trace_ioinst_sch_id("rsch", cssid, ssid, schid);
 765    sch = css_find_subch(m, cssid, ssid, schid);
 766    if (sch && css_subch_visible(sch)) {
 767        ret = css_do_rsch(sch);
 768    }
 769    switch (ret) {
 770    case -ENODEV:
 771        cc = 3;
 772        break;
 773    case -EINVAL:
 774        cc = 2;
 775        break;
 776    case 0:
 777        cc = 0;
 778        break;
 779    default:
 780        cc = 1;
 781        break;
 782    }
 783    setcc(cpu, cc);
 784}
 785
 786#define RCHP_REG1_RES(_reg) (_reg & 0x00000000ff00ff00)
 787#define RCHP_REG1_CSSID(_reg) ((_reg & 0x0000000000ff0000) >> 16)
 788#define RCHP_REG1_CHPID(_reg) (_reg & 0x00000000000000ff)
 789void ioinst_handle_rchp(S390CPU *cpu, uint64_t reg1)
 790{
 791    int cc;
 792    uint8_t cssid;
 793    uint8_t chpid;
 794    int ret;
 795    CPUS390XState *env = &cpu->env;
 796
 797    if (RCHP_REG1_RES(reg1)) {
 798        program_interrupt(env, PGM_OPERAND, 2);
 799        return;
 800    }
 801
 802    cssid = RCHP_REG1_CSSID(reg1);
 803    chpid = RCHP_REG1_CHPID(reg1);
 804
 805    trace_ioinst_chp_id("rchp", cssid, chpid);
 806
 807    ret = css_do_rchp(cssid, chpid);
 808
 809    switch (ret) {
 810    case -ENODEV:
 811        cc = 3;
 812        break;
 813    case -EBUSY:
 814        cc = 2;
 815        break;
 816    case 0:
 817        cc = 0;
 818        break;
 819    default:
 820        /* Invalid channel subsystem. */
 821        program_interrupt(env, PGM_OPERAND, 2);
 822        return;
 823    }
 824    setcc(cpu, cc);
 825}
 826
 827#define SAL_REG1_INVALID(_reg) (_reg & 0x0000000080000000)
 828void ioinst_handle_sal(S390CPU *cpu, uint64_t reg1)
 829{
 830    /* We do not provide address limit checking, so let's suppress it. */
 831    if (SAL_REG1_INVALID(reg1) || reg1 & 0x000000000000ffff) {
 832        program_interrupt(&cpu->env, PGM_OPERAND, 2);
 833    }
 834}
 835