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