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