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