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