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, 4);
  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, 4);
  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, 4);
 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, 4);
 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, 4);
 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    /* We don't support MIDA. */
 205    if (orb->ctrl1 & ORB_CTRL1_MASK_MIDAW) {
 206        return 0;
 207    }
 208    if ((orb->cpa & HIGH_ORDER_BIT) != 0) {
 209        return 0;
 210    }
 211    return 1;
 212}
 213
 214void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb)
 215{
 216    int cssid, ssid, schid, m;
 217    SubchDev *sch;
 218    ORB orig_orb, orb;
 219    uint64_t addr;
 220    int ret = -ENODEV;
 221    int cc;
 222    CPUS390XState *env = &cpu->env;
 223    uint8_t ar;
 224
 225    addr = decode_basedisp_s(env, ipb, &ar);
 226    if (addr & 3) {
 227        program_interrupt(env, PGM_SPECIFICATION, 4);
 228        return;
 229    }
 230    if (s390_cpu_virt_mem_read(cpu, addr, ar, &orig_orb, sizeof(orb))) {
 231        return;
 232    }
 233    copy_orb_from_guest(&orb, &orig_orb);
 234    if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid) ||
 235        !ioinst_orb_valid(&orb)) {
 236        program_interrupt(env, PGM_OPERAND, 4);
 237        return;
 238    }
 239    trace_ioinst_sch_id("ssch", cssid, ssid, schid);
 240    sch = css_find_subch(m, cssid, ssid, schid);
 241    if (sch && css_subch_visible(sch)) {
 242        ret = css_do_ssch(sch, &orb);
 243    }
 244    switch (ret) {
 245    case -ENODEV:
 246        cc = 3;
 247        break;
 248    case -EBUSY:
 249        cc = 2;
 250        break;
 251    case -EFAULT:
 252        /*
 253         * TODO:
 254         * I'm wondering whether there is something better
 255         * to do for us here (like setting some device or
 256         * subchannel status).
 257         */
 258        program_interrupt(env, PGM_ADDRESSING, 4);
 259        return;
 260    case 0:
 261        cc = 0;
 262        break;
 263    default:
 264        cc = 1;
 265        break;
 266    }
 267    setcc(cpu, cc);
 268}
 269
 270void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb)
 271{
 272    CRW crw;
 273    uint64_t addr;
 274    int cc;
 275    CPUS390XState *env = &cpu->env;
 276    uint8_t ar;
 277
 278    addr = decode_basedisp_s(env, ipb, &ar);
 279    if (addr & 3) {
 280        program_interrupt(env, PGM_SPECIFICATION, 4);
 281        return;
 282    }
 283
 284    cc = css_do_stcrw(&crw);
 285    /* 0 - crw stored, 1 - zeroes stored */
 286
 287    if (s390_cpu_virt_mem_write(cpu, addr, ar, &crw, sizeof(crw)) == 0) {
 288        setcc(cpu, cc);
 289    } else if (cc == 0) {
 290        /* Write failed: requeue CRW since STCRW is a suppressing instruction */
 291        css_undo_stcrw(&crw);
 292    }
 293}
 294
 295void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb)
 296{
 297    int cssid, ssid, schid, m;
 298    SubchDev *sch;
 299    uint64_t addr;
 300    int cc;
 301    SCHIB schib;
 302    CPUS390XState *env = &cpu->env;
 303    uint8_t ar;
 304
 305    addr = decode_basedisp_s(env, ipb, &ar);
 306    if (addr & 3) {
 307        program_interrupt(env, PGM_SPECIFICATION, 4);
 308        return;
 309    }
 310
 311    if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
 312        /*
 313         * As operand exceptions have a lower priority than access exceptions,
 314         * we check whether the memory area is writeable (injecting the
 315         * access execption if it is not) first.
 316         */
 317        if (!s390_cpu_virt_mem_check_write(cpu, addr, ar, sizeof(schib))) {
 318            program_interrupt(env, PGM_OPERAND, 4);
 319        }
 320        return;
 321    }
 322    trace_ioinst_sch_id("stsch", cssid, ssid, schid);
 323    sch = css_find_subch(m, cssid, ssid, schid);
 324    if (sch) {
 325        if (css_subch_visible(sch)) {
 326            css_do_stsch(sch, &schib);
 327            cc = 0;
 328        } else {
 329            /* Indicate no more subchannels in this css/ss */
 330            cc = 3;
 331        }
 332    } else {
 333        if (css_schid_final(m, cssid, ssid, schid)) {
 334            cc = 3; /* No more subchannels in this css/ss */
 335        } else {
 336            /* Store an empty schib. */
 337            memset(&schib, 0, sizeof(schib));
 338            cc = 0;
 339        }
 340    }
 341    if (cc != 3) {
 342        if (s390_cpu_virt_mem_write(cpu, addr, ar, &schib,
 343                                    sizeof(schib)) != 0) {
 344            return;
 345        }
 346    } else {
 347        /* Access exceptions have a higher priority than cc3 */
 348        if (s390_cpu_virt_mem_check_write(cpu, addr, ar, sizeof(schib)) != 0) {
 349            return;
 350        }
 351    }
 352    setcc(cpu, cc);
 353}
 354
 355int ioinst_handle_tsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb)
 356{
 357    CPUS390XState *env = &cpu->env;
 358    int cssid, ssid, schid, m;
 359    SubchDev *sch;
 360    IRB irb;
 361    uint64_t addr;
 362    int cc, irb_len;
 363    uint8_t ar;
 364
 365    if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
 366        program_interrupt(env, PGM_OPERAND, 4);
 367        return -EIO;
 368    }
 369    trace_ioinst_sch_id("tsch", cssid, ssid, schid);
 370    addr = decode_basedisp_s(env, ipb, &ar);
 371    if (addr & 3) {
 372        program_interrupt(env, PGM_SPECIFICATION, 4);
 373        return -EIO;
 374    }
 375
 376    sch = css_find_subch(m, cssid, ssid, schid);
 377    if (sch && css_subch_visible(sch)) {
 378        cc = css_do_tsch_get_irb(sch, &irb, &irb_len);
 379    } else {
 380        cc = 3;
 381    }
 382    /* 0 - status pending, 1 - not status pending, 3 - not operational */
 383    if (cc != 3) {
 384        if (s390_cpu_virt_mem_write(cpu, addr, ar, &irb, irb_len) != 0) {
 385            return -EFAULT;
 386        }
 387        css_do_tsch_update_subch(sch);
 388    } else {
 389        irb_len = sizeof(irb) - sizeof(irb.emw);
 390        /* Access exceptions have a higher priority than cc3 */
 391        if (s390_cpu_virt_mem_check_write(cpu, addr, ar, irb_len) != 0) {
 392            return -EFAULT;
 393        }
 394    }
 395
 396    setcc(cpu, cc);
 397    return 0;
 398}
 399
 400typedef struct ChscReq {
 401    uint16_t len;
 402    uint16_t command;
 403    uint32_t param0;
 404    uint32_t param1;
 405    uint32_t param2;
 406} QEMU_PACKED ChscReq;
 407
 408typedef struct ChscResp {
 409    uint16_t len;
 410    uint16_t code;
 411    uint32_t param;
 412    char data[0];
 413} QEMU_PACKED ChscResp;
 414
 415#define CHSC_MIN_RESP_LEN 0x0008
 416
 417#define CHSC_SCPD 0x0002
 418#define CHSC_SCSC 0x0010
 419#define CHSC_SDA  0x0031
 420#define CHSC_SEI  0x000e
 421
 422#define CHSC_SCPD_0_M 0x20000000
 423#define CHSC_SCPD_0_C 0x10000000
 424#define CHSC_SCPD_0_FMT 0x0f000000
 425#define CHSC_SCPD_0_CSSID 0x00ff0000
 426#define CHSC_SCPD_0_RFMT 0x00000f00
 427#define CHSC_SCPD_0_RES 0xc000f000
 428#define CHSC_SCPD_1_RES 0xffffff00
 429#define CHSC_SCPD_01_CHPID 0x000000ff
 430static void ioinst_handle_chsc_scpd(ChscReq *req, ChscResp *res)
 431{
 432    uint16_t len = be16_to_cpu(req->len);
 433    uint32_t param0 = be32_to_cpu(req->param0);
 434    uint32_t param1 = be32_to_cpu(req->param1);
 435    uint16_t resp_code;
 436    int rfmt;
 437    uint16_t cssid;
 438    uint8_t f_chpid, l_chpid;
 439    int desc_size;
 440    int m;
 441
 442    rfmt = (param0 & CHSC_SCPD_0_RFMT) >> 8;
 443    if ((rfmt == 0) ||  (rfmt == 1)) {
 444        rfmt = !!(param0 & CHSC_SCPD_0_C);
 445    }
 446    if ((len != 0x0010) || (param0 & CHSC_SCPD_0_RES) ||
 447        (param1 & CHSC_SCPD_1_RES) || req->param2) {
 448        resp_code = 0x0003;
 449        goto out_err;
 450    }
 451    if (param0 & CHSC_SCPD_0_FMT) {
 452        resp_code = 0x0007;
 453        goto out_err;
 454    }
 455    cssid = (param0 & CHSC_SCPD_0_CSSID) >> 16;
 456    m = param0 & CHSC_SCPD_0_M;
 457    if (cssid != 0) {
 458        if (!m || !css_present(cssid)) {
 459            resp_code = 0x0008;
 460            goto out_err;
 461        }
 462    }
 463    f_chpid = param0 & CHSC_SCPD_01_CHPID;
 464    l_chpid = param1 & CHSC_SCPD_01_CHPID;
 465    if (l_chpid < f_chpid) {
 466        resp_code = 0x0003;
 467        goto out_err;
 468    }
 469    /* css_collect_chp_desc() is endian-aware */
 470    desc_size = css_collect_chp_desc(m, cssid, f_chpid, l_chpid, rfmt,
 471                                     &res->data);
 472    res->code = cpu_to_be16(0x0001);
 473    res->len = cpu_to_be16(8 + desc_size);
 474    res->param = cpu_to_be32(rfmt);
 475    return;
 476
 477  out_err:
 478    res->code = cpu_to_be16(resp_code);
 479    res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
 480    res->param = cpu_to_be32(rfmt);
 481}
 482
 483#define CHSC_SCSC_0_M 0x20000000
 484#define CHSC_SCSC_0_FMT 0x000f0000
 485#define CHSC_SCSC_0_CSSID 0x0000ff00
 486#define CHSC_SCSC_0_RES 0xdff000ff
 487static void ioinst_handle_chsc_scsc(ChscReq *req, ChscResp *res)
 488{
 489    uint16_t len = be16_to_cpu(req->len);
 490    uint32_t param0 = be32_to_cpu(req->param0);
 491    uint8_t cssid;
 492    uint16_t resp_code;
 493    uint32_t general_chars[510];
 494    uint32_t chsc_chars[508];
 495
 496    if (len != 0x0010) {
 497        resp_code = 0x0003;
 498        goto out_err;
 499    }
 500
 501    if (param0 & CHSC_SCSC_0_FMT) {
 502        resp_code = 0x0007;
 503        goto out_err;
 504    }
 505    cssid = (param0 & CHSC_SCSC_0_CSSID) >> 8;
 506    if (cssid != 0) {
 507        if (!(param0 & CHSC_SCSC_0_M) || !css_present(cssid)) {
 508            resp_code = 0x0008;
 509            goto out_err;
 510        }
 511    }
 512    if ((param0 & CHSC_SCSC_0_RES) || req->param1 || req->param2) {
 513        resp_code = 0x0003;
 514        goto out_err;
 515    }
 516    res->code = cpu_to_be16(0x0001);
 517    res->len = cpu_to_be16(4080);
 518    res->param = 0;
 519
 520    memset(general_chars, 0, sizeof(general_chars));
 521    memset(chsc_chars, 0, sizeof(chsc_chars));
 522
 523    general_chars[0] = cpu_to_be32(0x03000000);
 524    general_chars[1] = cpu_to_be32(0x00079000);
 525    general_chars[3] = cpu_to_be32(0x00080000);
 526
 527    chsc_chars[0] = cpu_to_be32(0x40000000);
 528    chsc_chars[3] = cpu_to_be32(0x00040000);
 529
 530    memcpy(res->data, general_chars, sizeof(general_chars));
 531    memcpy(res->data + sizeof(general_chars), chsc_chars, sizeof(chsc_chars));
 532    return;
 533
 534  out_err:
 535    res->code = cpu_to_be16(resp_code);
 536    res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
 537    res->param = 0;
 538}
 539
 540#define CHSC_SDA_0_FMT 0x0f000000
 541#define CHSC_SDA_0_OC 0x0000ffff
 542#define CHSC_SDA_0_RES 0xf0ff0000
 543#define CHSC_SDA_OC_MCSSE 0x0
 544#define CHSC_SDA_OC_MSS 0x2
 545static void ioinst_handle_chsc_sda(ChscReq *req, ChscResp *res)
 546{
 547    uint16_t resp_code = 0x0001;
 548    uint16_t len = be16_to_cpu(req->len);
 549    uint32_t param0 = be32_to_cpu(req->param0);
 550    uint16_t oc;
 551    int ret;
 552
 553    if ((len != 0x0400) || (param0 & CHSC_SDA_0_RES)) {
 554        resp_code = 0x0003;
 555        goto out;
 556    }
 557
 558    if (param0 & CHSC_SDA_0_FMT) {
 559        resp_code = 0x0007;
 560        goto out;
 561    }
 562
 563    oc = param0 & CHSC_SDA_0_OC;
 564    switch (oc) {
 565    case CHSC_SDA_OC_MCSSE:
 566        ret = css_enable_mcsse();
 567        if (ret == -EINVAL) {
 568            resp_code = 0x0101;
 569            goto out;
 570        }
 571        break;
 572    case CHSC_SDA_OC_MSS:
 573        ret = css_enable_mss();
 574        if (ret == -EINVAL) {
 575            resp_code = 0x0101;
 576            goto out;
 577        }
 578        break;
 579    default:
 580        resp_code = 0x0003;
 581        goto out;
 582    }
 583
 584out:
 585    res->code = cpu_to_be16(resp_code);
 586    res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
 587    res->param = 0;
 588}
 589
 590static int chsc_sei_nt0_get_event(void *res)
 591{
 592    /* no events yet */
 593    return 1;
 594}
 595
 596static int chsc_sei_nt0_have_event(void)
 597{
 598    /* no events yet */
 599    return 0;
 600}
 601
 602#define CHSC_SEI_NT0    (1ULL << 63)
 603#define CHSC_SEI_NT2    (1ULL << 61)
 604static void ioinst_handle_chsc_sei(ChscReq *req, ChscResp *res)
 605{
 606    uint64_t selection_mask = ldq_p(&req->param1);
 607    uint8_t *res_flags = (uint8_t *)res->data;
 608    int have_event = 0;
 609    int have_more = 0;
 610
 611    /* regarding architecture nt0 can not be masked */
 612    have_event = !chsc_sei_nt0_get_event(res);
 613    have_more = chsc_sei_nt0_have_event();
 614
 615    if (selection_mask & CHSC_SEI_NT2) {
 616        if (!have_event) {
 617            have_event = !chsc_sei_nt2_get_event(res);
 618        }
 619
 620        if (!have_more) {
 621            have_more = chsc_sei_nt2_have_event();
 622        }
 623    }
 624
 625    if (have_event) {
 626        res->code = cpu_to_be16(0x0001);
 627        if (have_more) {
 628            (*res_flags) |= 0x80;
 629        } else {
 630            (*res_flags) &= ~0x80;
 631            css_clear_sei_pending();
 632        }
 633    } else {
 634        res->code = cpu_to_be16(0x0005);
 635        res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
 636    }
 637}
 638
 639static void ioinst_handle_chsc_unimplemented(ChscResp *res)
 640{
 641    res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
 642    res->code = cpu_to_be16(0x0004);
 643    res->param = 0;
 644}
 645
 646void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb)
 647{
 648    ChscReq *req;
 649    ChscResp *res;
 650    uint64_t addr;
 651    int reg;
 652    uint16_t len;
 653    uint16_t command;
 654    CPUS390XState *env = &cpu->env;
 655    uint8_t buf[TARGET_PAGE_SIZE];
 656
 657    trace_ioinst("chsc");
 658    reg = (ipb >> 20) & 0x00f;
 659    addr = env->regs[reg];
 660    /* Page boundary? */
 661    if (addr & 0xfff) {
 662        program_interrupt(env, PGM_SPECIFICATION, 4);
 663        return;
 664    }
 665    /*
 666     * Reading sizeof(ChscReq) bytes is currently enough for all of our
 667     * present CHSC sub-handlers ... if we ever need more, we should take
 668     * care of req->len here first.
 669     */
 670    if (s390_cpu_virt_mem_read(cpu, addr, reg, buf, sizeof(ChscReq))) {
 671        return;
 672    }
 673    req = (ChscReq *)buf;
 674    len = be16_to_cpu(req->len);
 675    /* Length field valid? */
 676    if ((len < 16) || (len > 4088) || (len & 7)) {
 677        program_interrupt(env, PGM_OPERAND, 4);
 678        return;
 679    }
 680    memset((char *)req + len, 0, TARGET_PAGE_SIZE - len);
 681    res = (void *)((char *)req + len);
 682    command = be16_to_cpu(req->command);
 683    trace_ioinst_chsc_cmd(command, len);
 684    switch (command) {
 685    case CHSC_SCSC:
 686        ioinst_handle_chsc_scsc(req, res);
 687        break;
 688    case CHSC_SCPD:
 689        ioinst_handle_chsc_scpd(req, res);
 690        break;
 691    case CHSC_SDA:
 692        ioinst_handle_chsc_sda(req, res);
 693        break;
 694    case CHSC_SEI:
 695        ioinst_handle_chsc_sei(req, res);
 696        break;
 697    default:
 698        ioinst_handle_chsc_unimplemented(res);
 699        break;
 700    }
 701
 702    if (!s390_cpu_virt_mem_write(cpu, addr + len, reg, res,
 703                                 be16_to_cpu(res->len))) {
 704        setcc(cpu, 0);    /* Command execution complete */
 705    }
 706}
 707
 708int ioinst_handle_tpi(S390CPU *cpu, uint32_t ipb)
 709{
 710    CPUS390XState *env = &cpu->env;
 711    uint64_t addr;
 712    int lowcore;
 713    IOIntCode int_code;
 714    hwaddr len;
 715    int ret;
 716    uint8_t ar;
 717
 718    trace_ioinst("tpi");
 719    addr = decode_basedisp_s(env, ipb, &ar);
 720    if (addr & 3) {
 721        program_interrupt(env, PGM_SPECIFICATION, 4);
 722        return -EIO;
 723    }
 724
 725    lowcore = addr ? 0 : 1;
 726    len = lowcore ? 8 /* two words */ : 12 /* three words */;
 727    ret = css_do_tpi(&int_code, lowcore);
 728    if (ret == 1) {
 729        s390_cpu_virt_mem_write(cpu, lowcore ? 184 : addr, ar, &int_code, len);
 730    }
 731    return ret;
 732}
 733
 734#define SCHM_REG1_RES(_reg) (_reg & 0x000000000ffffffc)
 735#define SCHM_REG1_MBK(_reg) ((_reg & 0x00000000f0000000) >> 28)
 736#define SCHM_REG1_UPD(_reg) ((_reg & 0x0000000000000002) >> 1)
 737#define SCHM_REG1_DCT(_reg) (_reg & 0x0000000000000001)
 738
 739void ioinst_handle_schm(S390CPU *cpu, uint64_t reg1, uint64_t reg2,
 740                        uint32_t ipb)
 741{
 742    uint8_t mbk;
 743    int update;
 744    int dct;
 745    CPUS390XState *env = &cpu->env;
 746
 747    trace_ioinst("schm");
 748
 749    if (SCHM_REG1_RES(reg1)) {
 750        program_interrupt(env, PGM_OPERAND, 4);
 751        return;
 752    }
 753
 754    mbk = SCHM_REG1_MBK(reg1);
 755    update = SCHM_REG1_UPD(reg1);
 756    dct = SCHM_REG1_DCT(reg1);
 757
 758    if (update && (reg2 & 0x000000000000001f)) {
 759        program_interrupt(env, PGM_OPERAND, 4);
 760        return;
 761    }
 762
 763    css_do_schm(mbk, update, dct, update ? reg2 : 0);
 764}
 765
 766void ioinst_handle_rsch(S390CPU *cpu, uint64_t reg1)
 767{
 768    int cssid, ssid, schid, m;
 769    SubchDev *sch;
 770    int ret = -ENODEV;
 771    int cc;
 772
 773    if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
 774        program_interrupt(&cpu->env, PGM_OPERAND, 4);
 775        return;
 776    }
 777    trace_ioinst_sch_id("rsch", cssid, ssid, schid);
 778    sch = css_find_subch(m, cssid, ssid, schid);
 779    if (sch && css_subch_visible(sch)) {
 780        ret = css_do_rsch(sch);
 781    }
 782    switch (ret) {
 783    case -ENODEV:
 784        cc = 3;
 785        break;
 786    case -EINVAL:
 787        cc = 2;
 788        break;
 789    case 0:
 790        cc = 0;
 791        break;
 792    default:
 793        cc = 1;
 794        break;
 795    }
 796    setcc(cpu, cc);
 797}
 798
 799#define RCHP_REG1_RES(_reg) (_reg & 0x00000000ff00ff00)
 800#define RCHP_REG1_CSSID(_reg) ((_reg & 0x0000000000ff0000) >> 16)
 801#define RCHP_REG1_CHPID(_reg) (_reg & 0x00000000000000ff)
 802void ioinst_handle_rchp(S390CPU *cpu, uint64_t reg1)
 803{
 804    int cc;
 805    uint8_t cssid;
 806    uint8_t chpid;
 807    int ret;
 808    CPUS390XState *env = &cpu->env;
 809
 810    if (RCHP_REG1_RES(reg1)) {
 811        program_interrupt(env, PGM_OPERAND, 4);
 812        return;
 813    }
 814
 815    cssid = RCHP_REG1_CSSID(reg1);
 816    chpid = RCHP_REG1_CHPID(reg1);
 817
 818    trace_ioinst_chp_id("rchp", cssid, chpid);
 819
 820    ret = css_do_rchp(cssid, chpid);
 821
 822    switch (ret) {
 823    case -ENODEV:
 824        cc = 3;
 825        break;
 826    case -EBUSY:
 827        cc = 2;
 828        break;
 829    case 0:
 830        cc = 0;
 831        break;
 832    default:
 833        /* Invalid channel subsystem. */
 834        program_interrupt(env, PGM_OPERAND, 4);
 835        return;
 836    }
 837    setcc(cpu, cc);
 838}
 839
 840#define SAL_REG1_INVALID(_reg) (_reg & 0x0000000080000000)
 841void ioinst_handle_sal(S390CPU *cpu, uint64_t reg1)
 842{
 843    /* We do not provide address limit checking, so let's suppress it. */
 844    if (SAL_REG1_INVALID(reg1) || reg1 & 0x000000000000ffff) {
 845        program_interrupt(&cpu->env, PGM_OPERAND, 4);
 846    }
 847}
 848