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