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