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