s390x: refactor error handling for HSCH handler
[qemu/kevin.git] / target / s390x / ioinst.c
blob8e4dacafd886dc94c641520a2579da94b418c995
1 /*
2 * I/O instructions for S/390
4 * Copyright 2012, 2015 IBM Corp.
5 * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
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.
12 #include "qemu/osdep.h"
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"
20 int ioinst_disassemble_sch_ident(uint32_t value, int *m, int *cssid, int *ssid,
21 int *schid)
23 if (!IOINST_SCHID_ONE(value)) {
24 return -EINVAL;
26 if (!IOINST_SCHID_M(value)) {
27 if (IOINST_SCHID_CSSID(value)) {
28 return -EINVAL;
30 *cssid = 0;
31 *m = 0;
32 } else {
33 *cssid = IOINST_SCHID_CSSID(value);
34 *m = 1;
36 *ssid = IOINST_SCHID_SSID(value);
37 *schid = IOINST_SCHID_NR(value);
38 return 0;
41 void ioinst_handle_xsch(S390CPU *cpu, uint64_t reg1)
43 int cssid, ssid, schid, m;
44 SubchDev *sch;
46 if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
47 program_interrupt(&cpu->env, PGM_OPERAND, 4);
48 return;
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;
56 setcc(cpu, css_do_xsch(sch));
59 void ioinst_handle_csch(S390CPU *cpu, uint64_t reg1)
61 int cssid, ssid, schid, m;
62 SubchDev *sch;
64 if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
65 program_interrupt(&cpu->env, PGM_OPERAND, 4);
66 return;
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;
74 setcc(cpu, css_do_csch(sch));
77 void ioinst_handle_hsch(S390CPU *cpu, uint64_t reg1)
79 int cssid, ssid, schid, m;
80 SubchDev *sch;
82 if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
83 program_interrupt(&cpu->env, PGM_OPERAND, 4);
84 return;
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;
92 setcc(cpu, css_do_hsch(sch));
95 static int ioinst_schib_valid(SCHIB *schib)
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;
101 /* Disallow extended measurements for now. */
102 if (be32_to_cpu(schib->pmcw.chars) & PMCW_CHARS_MASK_XMWME) {
103 return 0;
105 return 1;
108 void ioinst_handle_msch(S390CPU *cpu, uint64_t reg1, uint32_t ipb)
110 int cssid, ssid, schid, m;
111 SubchDev *sch;
112 SCHIB schib;
113 uint64_t addr;
114 int ret = -ENODEV;
115 int cc;
116 CPUS390XState *env = &cpu->env;
117 uint8_t ar;
119 addr = decode_basedisp_s(env, ipb, &ar);
120 if (addr & 3) {
121 program_interrupt(env, PGM_SPECIFICATION, 4);
122 return;
124 if (s390_cpu_virt_mem_read(cpu, addr, ar, &schib, sizeof(schib))) {
125 return;
127 if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid) ||
128 !ioinst_schib_valid(&schib)) {
129 program_interrupt(env, PGM_OPERAND, 4);
130 return;
132 trace_ioinst_sch_id("msch", cssid, ssid, schid);
133 sch = css_find_subch(m, cssid, ssid, schid);
134 if (sch && css_subch_visible(sch)) {
135 ret = css_do_msch(sch, &schib);
137 switch (ret) {
138 case -ENODEV:
139 cc = 3;
140 break;
141 case -EBUSY:
142 cc = 2;
143 break;
144 case 0:
145 cc = 0;
146 break;
147 default:
148 cc = 1;
149 break;
151 setcc(cpu, cc);
154 static void copy_orb_from_guest(ORB *dest, const ORB *src)
156 dest->intparm = be32_to_cpu(src->intparm);
157 dest->ctrl0 = be16_to_cpu(src->ctrl0);
158 dest->lpm = src->lpm;
159 dest->ctrl1 = src->ctrl1;
160 dest->cpa = be32_to_cpu(src->cpa);
163 static int ioinst_orb_valid(ORB *orb)
165 if ((orb->ctrl0 & ORB_CTRL0_MASK_INVALID) ||
166 (orb->ctrl1 & ORB_CTRL1_MASK_INVALID)) {
167 return 0;
169 /* We don't support MIDA. */
170 if (orb->ctrl1 & ORB_CTRL1_MASK_MIDAW) {
171 return 0;
173 if ((orb->cpa & HIGH_ORDER_BIT) != 0) {
174 return 0;
176 return 1;
179 void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb)
181 int cssid, ssid, schid, m;
182 SubchDev *sch;
183 ORB orig_orb, orb;
184 uint64_t addr;
185 CPUS390XState *env = &cpu->env;
186 uint8_t ar;
188 addr = decode_basedisp_s(env, ipb, &ar);
189 if (addr & 3) {
190 program_interrupt(env, PGM_SPECIFICATION, 4);
191 return;
193 if (s390_cpu_virt_mem_read(cpu, addr, ar, &orig_orb, sizeof(orb))) {
194 return;
196 copy_orb_from_guest(&orb, &orig_orb);
197 if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid) ||
198 !ioinst_orb_valid(&orb)) {
199 program_interrupt(env, PGM_OPERAND, 4);
200 return;
202 trace_ioinst_sch_id("ssch", cssid, ssid, schid);
203 sch = css_find_subch(m, cssid, ssid, schid);
204 if (!sch || !css_subch_visible(sch)) {
205 setcc(cpu, 3);
206 return;
208 setcc(cpu, css_do_ssch(sch, &orb));
211 void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb)
213 CRW crw;
214 uint64_t addr;
215 int cc;
216 CPUS390XState *env = &cpu->env;
217 uint8_t ar;
219 addr = decode_basedisp_s(env, ipb, &ar);
220 if (addr & 3) {
221 program_interrupt(env, PGM_SPECIFICATION, 4);
222 return;
225 cc = css_do_stcrw(&crw);
226 /* 0 - crw stored, 1 - zeroes stored */
228 if (s390_cpu_virt_mem_write(cpu, addr, ar, &crw, sizeof(crw)) == 0) {
229 setcc(cpu, cc);
230 } else if (cc == 0) {
231 /* Write failed: requeue CRW since STCRW is a suppressing instruction */
232 css_undo_stcrw(&crw);
236 void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb)
238 int cssid, ssid, schid, m;
239 SubchDev *sch;
240 uint64_t addr;
241 int cc;
242 SCHIB schib;
243 CPUS390XState *env = &cpu->env;
244 uint8_t ar;
246 addr = decode_basedisp_s(env, ipb, &ar);
247 if (addr & 3) {
248 program_interrupt(env, PGM_SPECIFICATION, 4);
249 return;
252 if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
254 * As operand exceptions have a lower priority than access exceptions,
255 * we check whether the memory area is writeable (injecting the
256 * access execption if it is not) first.
258 if (!s390_cpu_virt_mem_check_write(cpu, addr, ar, sizeof(schib))) {
259 program_interrupt(env, PGM_OPERAND, 4);
261 return;
263 trace_ioinst_sch_id("stsch", cssid, ssid, schid);
264 sch = css_find_subch(m, cssid, ssid, schid);
265 if (sch) {
266 if (css_subch_visible(sch)) {
267 css_do_stsch(sch, &schib);
268 cc = 0;
269 } else {
270 /* Indicate no more subchannels in this css/ss */
271 cc = 3;
273 } else {
274 if (css_schid_final(m, cssid, ssid, schid)) {
275 cc = 3; /* No more subchannels in this css/ss */
276 } else {
277 /* Store an empty schib. */
278 memset(&schib, 0, sizeof(schib));
279 cc = 0;
282 if (cc != 3) {
283 if (s390_cpu_virt_mem_write(cpu, addr, ar, &schib,
284 sizeof(schib)) != 0) {
285 return;
287 } else {
288 /* Access exceptions have a higher priority than cc3 */
289 if (s390_cpu_virt_mem_check_write(cpu, addr, ar, sizeof(schib)) != 0) {
290 return;
293 setcc(cpu, cc);
296 int ioinst_handle_tsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb)
298 CPUS390XState *env = &cpu->env;
299 int cssid, ssid, schid, m;
300 SubchDev *sch;
301 IRB irb;
302 uint64_t addr;
303 int cc, irb_len;
304 uint8_t ar;
306 if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
307 program_interrupt(env, PGM_OPERAND, 4);
308 return -EIO;
310 trace_ioinst_sch_id("tsch", cssid, ssid, schid);
311 addr = decode_basedisp_s(env, ipb, &ar);
312 if (addr & 3) {
313 program_interrupt(env, PGM_SPECIFICATION, 4);
314 return -EIO;
317 sch = css_find_subch(m, cssid, ssid, schid);
318 if (sch && css_subch_visible(sch)) {
319 cc = css_do_tsch_get_irb(sch, &irb, &irb_len);
320 } else {
321 cc = 3;
323 /* 0 - status pending, 1 - not status pending, 3 - not operational */
324 if (cc != 3) {
325 if (s390_cpu_virt_mem_write(cpu, addr, ar, &irb, irb_len) != 0) {
326 return -EFAULT;
328 css_do_tsch_update_subch(sch);
329 } else {
330 irb_len = sizeof(irb) - sizeof(irb.emw);
331 /* Access exceptions have a higher priority than cc3 */
332 if (s390_cpu_virt_mem_check_write(cpu, addr, ar, irb_len) != 0) {
333 return -EFAULT;
337 setcc(cpu, cc);
338 return 0;
341 typedef struct ChscReq {
342 uint16_t len;
343 uint16_t command;
344 uint32_t param0;
345 uint32_t param1;
346 uint32_t param2;
347 } QEMU_PACKED ChscReq;
349 typedef struct ChscResp {
350 uint16_t len;
351 uint16_t code;
352 uint32_t param;
353 char data[0];
354 } QEMU_PACKED ChscResp;
356 #define CHSC_MIN_RESP_LEN 0x0008
358 #define CHSC_SCPD 0x0002
359 #define CHSC_SCSC 0x0010
360 #define CHSC_SDA 0x0031
361 #define CHSC_SEI 0x000e
363 #define CHSC_SCPD_0_M 0x20000000
364 #define CHSC_SCPD_0_C 0x10000000
365 #define CHSC_SCPD_0_FMT 0x0f000000
366 #define CHSC_SCPD_0_CSSID 0x00ff0000
367 #define CHSC_SCPD_0_RFMT 0x00000f00
368 #define CHSC_SCPD_0_RES 0xc000f000
369 #define CHSC_SCPD_1_RES 0xffffff00
370 #define CHSC_SCPD_01_CHPID 0x000000ff
371 static void ioinst_handle_chsc_scpd(ChscReq *req, ChscResp *res)
373 uint16_t len = be16_to_cpu(req->len);
374 uint32_t param0 = be32_to_cpu(req->param0);
375 uint32_t param1 = be32_to_cpu(req->param1);
376 uint16_t resp_code;
377 int rfmt;
378 uint16_t cssid;
379 uint8_t f_chpid, l_chpid;
380 int desc_size;
381 int m;
383 rfmt = (param0 & CHSC_SCPD_0_RFMT) >> 8;
384 if ((rfmt == 0) || (rfmt == 1)) {
385 rfmt = !!(param0 & CHSC_SCPD_0_C);
387 if ((len != 0x0010) || (param0 & CHSC_SCPD_0_RES) ||
388 (param1 & CHSC_SCPD_1_RES) || req->param2) {
389 resp_code = 0x0003;
390 goto out_err;
392 if (param0 & CHSC_SCPD_0_FMT) {
393 resp_code = 0x0007;
394 goto out_err;
396 cssid = (param0 & CHSC_SCPD_0_CSSID) >> 16;
397 m = param0 & CHSC_SCPD_0_M;
398 if (cssid != 0) {
399 if (!m || !css_present(cssid)) {
400 resp_code = 0x0008;
401 goto out_err;
404 f_chpid = param0 & CHSC_SCPD_01_CHPID;
405 l_chpid = param1 & CHSC_SCPD_01_CHPID;
406 if (l_chpid < f_chpid) {
407 resp_code = 0x0003;
408 goto out_err;
410 /* css_collect_chp_desc() is endian-aware */
411 desc_size = css_collect_chp_desc(m, cssid, f_chpid, l_chpid, rfmt,
412 &res->data);
413 res->code = cpu_to_be16(0x0001);
414 res->len = cpu_to_be16(8 + desc_size);
415 res->param = cpu_to_be32(rfmt);
416 return;
418 out_err:
419 res->code = cpu_to_be16(resp_code);
420 res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
421 res->param = cpu_to_be32(rfmt);
424 #define CHSC_SCSC_0_M 0x20000000
425 #define CHSC_SCSC_0_FMT 0x000f0000
426 #define CHSC_SCSC_0_CSSID 0x0000ff00
427 #define CHSC_SCSC_0_RES 0xdff000ff
428 static void ioinst_handle_chsc_scsc(ChscReq *req, ChscResp *res)
430 uint16_t len = be16_to_cpu(req->len);
431 uint32_t param0 = be32_to_cpu(req->param0);
432 uint8_t cssid;
433 uint16_t resp_code;
434 uint32_t general_chars[510];
435 uint32_t chsc_chars[508];
437 if (len != 0x0010) {
438 resp_code = 0x0003;
439 goto out_err;
442 if (param0 & CHSC_SCSC_0_FMT) {
443 resp_code = 0x0007;
444 goto out_err;
446 cssid = (param0 & CHSC_SCSC_0_CSSID) >> 8;
447 if (cssid != 0) {
448 if (!(param0 & CHSC_SCSC_0_M) || !css_present(cssid)) {
449 resp_code = 0x0008;
450 goto out_err;
453 if ((param0 & CHSC_SCSC_0_RES) || req->param1 || req->param2) {
454 resp_code = 0x0003;
455 goto out_err;
457 res->code = cpu_to_be16(0x0001);
458 res->len = cpu_to_be16(4080);
459 res->param = 0;
461 memset(general_chars, 0, sizeof(general_chars));
462 memset(chsc_chars, 0, sizeof(chsc_chars));
464 general_chars[0] = cpu_to_be32(0x03000000);
465 general_chars[1] = cpu_to_be32(0x00079000);
466 general_chars[3] = cpu_to_be32(0x00080000);
468 chsc_chars[0] = cpu_to_be32(0x40000000);
469 chsc_chars[3] = cpu_to_be32(0x00040000);
471 memcpy(res->data, general_chars, sizeof(general_chars));
472 memcpy(res->data + sizeof(general_chars), chsc_chars, sizeof(chsc_chars));
473 return;
475 out_err:
476 res->code = cpu_to_be16(resp_code);
477 res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
478 res->param = 0;
481 #define CHSC_SDA_0_FMT 0x0f000000
482 #define CHSC_SDA_0_OC 0x0000ffff
483 #define CHSC_SDA_0_RES 0xf0ff0000
484 #define CHSC_SDA_OC_MCSSE 0x0
485 #define CHSC_SDA_OC_MSS 0x2
486 static void ioinst_handle_chsc_sda(ChscReq *req, ChscResp *res)
488 uint16_t resp_code = 0x0001;
489 uint16_t len = be16_to_cpu(req->len);
490 uint32_t param0 = be32_to_cpu(req->param0);
491 uint16_t oc;
492 int ret;
494 if ((len != 0x0400) || (param0 & CHSC_SDA_0_RES)) {
495 resp_code = 0x0003;
496 goto out;
499 if (param0 & CHSC_SDA_0_FMT) {
500 resp_code = 0x0007;
501 goto out;
504 oc = param0 & CHSC_SDA_0_OC;
505 switch (oc) {
506 case CHSC_SDA_OC_MCSSE:
507 ret = css_enable_mcsse();
508 if (ret == -EINVAL) {
509 resp_code = 0x0101;
510 goto out;
512 break;
513 case CHSC_SDA_OC_MSS:
514 ret = css_enable_mss();
515 if (ret == -EINVAL) {
516 resp_code = 0x0101;
517 goto out;
519 break;
520 default:
521 resp_code = 0x0003;
522 goto out;
525 out:
526 res->code = cpu_to_be16(resp_code);
527 res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
528 res->param = 0;
531 static int chsc_sei_nt0_get_event(void *res)
533 /* no events yet */
534 return 1;
537 static int chsc_sei_nt0_have_event(void)
539 /* no events yet */
540 return 0;
543 static int chsc_sei_nt2_get_event(void *res)
545 if (s390_has_feat(S390_FEAT_ZPCI)) {
546 return pci_chsc_sei_nt2_get_event(res);
548 return 1;
551 static int chsc_sei_nt2_have_event(void)
553 if (s390_has_feat(S390_FEAT_ZPCI)) {
554 return pci_chsc_sei_nt2_have_event();
556 return 0;
559 #define CHSC_SEI_NT0 (1ULL << 63)
560 #define CHSC_SEI_NT2 (1ULL << 61)
561 static void ioinst_handle_chsc_sei(ChscReq *req, ChscResp *res)
563 uint64_t selection_mask = ldq_p(&req->param1);
564 uint8_t *res_flags = (uint8_t *)res->data;
565 int have_event = 0;
566 int have_more = 0;
568 /* regarding architecture nt0 can not be masked */
569 have_event = !chsc_sei_nt0_get_event(res);
570 have_more = chsc_sei_nt0_have_event();
572 if (selection_mask & CHSC_SEI_NT2) {
573 if (!have_event) {
574 have_event = !chsc_sei_nt2_get_event(res);
577 if (!have_more) {
578 have_more = chsc_sei_nt2_have_event();
582 if (have_event) {
583 res->code = cpu_to_be16(0x0001);
584 if (have_more) {
585 (*res_flags) |= 0x80;
586 } else {
587 (*res_flags) &= ~0x80;
588 css_clear_sei_pending();
590 } else {
591 res->code = cpu_to_be16(0x0005);
592 res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
596 static void ioinst_handle_chsc_unimplemented(ChscResp *res)
598 res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
599 res->code = cpu_to_be16(0x0004);
600 res->param = 0;
603 void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb)
605 ChscReq *req;
606 ChscResp *res;
607 uint64_t addr;
608 int reg;
609 uint16_t len;
610 uint16_t command;
611 CPUS390XState *env = &cpu->env;
612 uint8_t buf[TARGET_PAGE_SIZE];
614 trace_ioinst("chsc");
615 reg = (ipb >> 20) & 0x00f;
616 addr = env->regs[reg];
617 /* Page boundary? */
618 if (addr & 0xfff) {
619 program_interrupt(env, PGM_SPECIFICATION, 4);
620 return;
623 * Reading sizeof(ChscReq) bytes is currently enough for all of our
624 * present CHSC sub-handlers ... if we ever need more, we should take
625 * care of req->len here first.
627 if (s390_cpu_virt_mem_read(cpu, addr, reg, buf, sizeof(ChscReq))) {
628 return;
630 req = (ChscReq *)buf;
631 len = be16_to_cpu(req->len);
632 /* Length field valid? */
633 if ((len < 16) || (len > 4088) || (len & 7)) {
634 program_interrupt(env, PGM_OPERAND, 4);
635 return;
637 memset((char *)req + len, 0, TARGET_PAGE_SIZE - len);
638 res = (void *)((char *)req + len);
639 command = be16_to_cpu(req->command);
640 trace_ioinst_chsc_cmd(command, len);
641 switch (command) {
642 case CHSC_SCSC:
643 ioinst_handle_chsc_scsc(req, res);
644 break;
645 case CHSC_SCPD:
646 ioinst_handle_chsc_scpd(req, res);
647 break;
648 case CHSC_SDA:
649 ioinst_handle_chsc_sda(req, res);
650 break;
651 case CHSC_SEI:
652 ioinst_handle_chsc_sei(req, res);
653 break;
654 default:
655 ioinst_handle_chsc_unimplemented(res);
656 break;
659 if (!s390_cpu_virt_mem_write(cpu, addr + len, reg, res,
660 be16_to_cpu(res->len))) {
661 setcc(cpu, 0); /* Command execution complete */
665 int ioinst_handle_tpi(S390CPU *cpu, uint32_t ipb)
667 CPUS390XState *env = &cpu->env;
668 uint64_t addr;
669 int lowcore;
670 IOIntCode int_code;
671 hwaddr len;
672 int ret;
673 uint8_t ar;
675 trace_ioinst("tpi");
676 addr = decode_basedisp_s(env, ipb, &ar);
677 if (addr & 3) {
678 program_interrupt(env, PGM_SPECIFICATION, 4);
679 return -EIO;
682 lowcore = addr ? 0 : 1;
683 len = lowcore ? 8 /* two words */ : 12 /* three words */;
684 ret = css_do_tpi(&int_code, lowcore);
685 if (ret == 1) {
686 s390_cpu_virt_mem_write(cpu, lowcore ? 184 : addr, ar, &int_code, len);
688 return ret;
691 #define SCHM_REG1_RES(_reg) (_reg & 0x000000000ffffffc)
692 #define SCHM_REG1_MBK(_reg) ((_reg & 0x00000000f0000000) >> 28)
693 #define SCHM_REG1_UPD(_reg) ((_reg & 0x0000000000000002) >> 1)
694 #define SCHM_REG1_DCT(_reg) (_reg & 0x0000000000000001)
696 void ioinst_handle_schm(S390CPU *cpu, uint64_t reg1, uint64_t reg2,
697 uint32_t ipb)
699 uint8_t mbk;
700 int update;
701 int dct;
702 CPUS390XState *env = &cpu->env;
704 trace_ioinst("schm");
706 if (SCHM_REG1_RES(reg1)) {
707 program_interrupt(env, PGM_OPERAND, 4);
708 return;
711 mbk = SCHM_REG1_MBK(reg1);
712 update = SCHM_REG1_UPD(reg1);
713 dct = SCHM_REG1_DCT(reg1);
715 if (update && (reg2 & 0x000000000000001f)) {
716 program_interrupt(env, PGM_OPERAND, 4);
717 return;
720 css_do_schm(mbk, update, dct, update ? reg2 : 0);
723 void ioinst_handle_rsch(S390CPU *cpu, uint64_t reg1)
725 int cssid, ssid, schid, m;
726 SubchDev *sch;
728 if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
729 program_interrupt(&cpu->env, PGM_OPERAND, 4);
730 return;
732 trace_ioinst_sch_id("rsch", cssid, ssid, schid);
733 sch = css_find_subch(m, cssid, ssid, schid);
734 if (!sch || !css_subch_visible(sch)) {
735 setcc(cpu, 3);
736 return;
738 setcc(cpu, css_do_rsch(sch));
741 #define RCHP_REG1_RES(_reg) (_reg & 0x00000000ff00ff00)
742 #define RCHP_REG1_CSSID(_reg) ((_reg & 0x0000000000ff0000) >> 16)
743 #define RCHP_REG1_CHPID(_reg) (_reg & 0x00000000000000ff)
744 void ioinst_handle_rchp(S390CPU *cpu, uint64_t reg1)
746 int cc;
747 uint8_t cssid;
748 uint8_t chpid;
749 int ret;
750 CPUS390XState *env = &cpu->env;
752 if (RCHP_REG1_RES(reg1)) {
753 program_interrupt(env, PGM_OPERAND, 4);
754 return;
757 cssid = RCHP_REG1_CSSID(reg1);
758 chpid = RCHP_REG1_CHPID(reg1);
760 trace_ioinst_chp_id("rchp", cssid, chpid);
762 ret = css_do_rchp(cssid, chpid);
764 switch (ret) {
765 case -ENODEV:
766 cc = 3;
767 break;
768 case -EBUSY:
769 cc = 2;
770 break;
771 case 0:
772 cc = 0;
773 break;
774 default:
775 /* Invalid channel subsystem. */
776 program_interrupt(env, PGM_OPERAND, 4);
777 return;
779 setcc(cpu, cc);
782 #define SAL_REG1_INVALID(_reg) (_reg & 0x0000000080000000)
783 void ioinst_handle_sal(S390CPU *cpu, uint64_t reg1)
785 /* We do not provide address limit checking, so let's suppress it. */
786 if (SAL_REG1_INVALID(reg1) || reg1 & 0x000000000000ffff) {
787 program_interrupt(&cpu->env, PGM_OPERAND, 4);