ioinst.c (22669B)
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 ((be32_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}