]> Git Repo - qemu.git/blob - target-s390x/ioinst.c
s390x/css: Make schib parameter of css_do_msch const
[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 <[email protected]>
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 #include "hw/s390x/s390-pci-bus.h"
18
19 int ioinst_disassemble_sch_ident(uint32_t value, int *m, int *cssid, int *ssid,
20                                  int *schid)
21 {
22     if (!IOINST_SCHID_ONE(value)) {
23         return -EINVAL;
24     }
25     if (!IOINST_SCHID_M(value)) {
26         if (IOINST_SCHID_CSSID(value)) {
27             return -EINVAL;
28         }
29         *cssid = 0;
30         *m = 0;
31     } else {
32         *cssid = IOINST_SCHID_CSSID(value);
33         *m = 1;
34     }
35     *ssid = IOINST_SCHID_SSID(value);
36     *schid = IOINST_SCHID_NR(value);
37     return 0;
38 }
39
40 void ioinst_handle_xsch(S390CPU *cpu, uint64_t reg1)
41 {
42     int cssid, ssid, schid, m;
43     SubchDev *sch;
44     int ret = -ENODEV;
45     int cc;
46
47     if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
48         program_interrupt(&cpu->env, PGM_OPERAND, 2);
49         return;
50     }
51     trace_ioinst_sch_id("xsch", cssid, ssid, schid);
52     sch = css_find_subch(m, cssid, ssid, schid);
53     if (sch && css_subch_visible(sch)) {
54         ret = css_do_xsch(sch);
55     }
56     switch (ret) {
57     case -ENODEV:
58         cc = 3;
59         break;
60     case -EBUSY:
61         cc = 2;
62         break;
63     case 0:
64         cc = 0;
65         break;
66     default:
67         cc = 1;
68         break;
69     }
70     setcc(cpu, cc);
71 }
72
73 void ioinst_handle_csch(S390CPU *cpu, 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(&cpu->env, PGM_OPERAND, 2);
82         return;
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     setcc(cpu, cc);
95 }
96
97 void ioinst_handle_hsch(S390CPU *cpu, 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(&cpu->env, PGM_OPERAND, 2);
106         return;
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     setcc(cpu, cc);
128 }
129
130 static int ioinst_schib_valid(SCHIB *schib)
131 {
132     if ((schib->pmcw.flags & PMCW_FLAGS_MASK_INVALID) ||
133         (schib->pmcw.chars & PMCW_CHARS_MASK_INVALID)) {
134         return 0;
135     }
136     /* Disallow extended measurements for now. */
137     if (schib->pmcw.chars & PMCW_CHARS_MASK_XMWME) {
138         return 0;
139     }
140     return 1;
141 }
142
143 void ioinst_handle_msch(S390CPU *cpu, uint64_t reg1, uint32_t ipb)
144 {
145     int cssid, ssid, schid, m;
146     SubchDev *sch;
147     SCHIB *schib;
148     uint64_t addr;
149     int ret = -ENODEV;
150     int cc;
151     hwaddr len = sizeof(*schib);
152     CPUS390XState *env = &cpu->env;
153
154     addr = decode_basedisp_s(env, ipb);
155     if (addr & 3) {
156         program_interrupt(env, PGM_SPECIFICATION, 2);
157         return;
158     }
159     schib = s390_cpu_physical_memory_map(env, addr, &len, 0);
160     if (!schib || len != sizeof(*schib)) {
161         program_interrupt(env, PGM_ADDRESSING, 2);
162         goto out;
163     }
164     if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid) ||
165         !ioinst_schib_valid(schib)) {
166         program_interrupt(env, PGM_OPERAND, 2);
167         goto out;
168     }
169     trace_ioinst_sch_id("msch", cssid, ssid, schid);
170     sch = css_find_subch(m, cssid, ssid, schid);
171     if (sch && css_subch_visible(sch)) {
172         ret = css_do_msch(sch, schib);
173     }
174     switch (ret) {
175     case -ENODEV:
176         cc = 3;
177         break;
178     case -EBUSY:
179         cc = 2;
180         break;
181     case 0:
182         cc = 0;
183         break;
184     default:
185         cc = 1;
186         break;
187     }
188     setcc(cpu, cc);
189
190 out:
191     s390_cpu_physical_memory_unmap(env, schib, len, 0);
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 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     hwaddr len = sizeof(*orig_orb);
224     CPUS390XState *env = &cpu->env;
225
226     addr = decode_basedisp_s(env, ipb);
227     if (addr & 3) {
228         program_interrupt(env, PGM_SPECIFICATION, 2);
229         return;
230     }
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_ADDRESSING, 2);
234         goto out;
235     }
236     copy_orb_from_guest(&orb, orig_orb);
237     if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid) ||
238         !ioinst_orb_valid(&orb)) {
239         program_interrupt(env, PGM_OPERAND, 2);
240         goto out;
241     }
242     trace_ioinst_sch_id("ssch", cssid, ssid, schid);
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     setcc(cpu, cc);
262
263 out:
264     s390_cpu_physical_memory_unmap(env, orig_orb, len, 0);
265 }
266
267 void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb)
268 {
269     CRW *crw;
270     uint64_t addr;
271     int cc;
272     hwaddr len = sizeof(*crw);
273     CPUS390XState *env = &cpu->env;
274
275     addr = decode_basedisp_s(env, ipb);
276     if (addr & 3) {
277         program_interrupt(env, PGM_SPECIFICATION, 2);
278         return;
279     }
280     crw = s390_cpu_physical_memory_map(env, addr, &len, 1);
281     if (!crw || len != sizeof(*crw)) {
282         program_interrupt(env, PGM_ADDRESSING, 2);
283         goto out;
284     }
285     cc = css_do_stcrw(crw);
286     /* 0 - crw stored, 1 - zeroes stored */
287     setcc(cpu, cc);
288
289 out:
290     s390_cpu_physical_memory_unmap(env, crw, len, 1);
291 }
292
293 void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb)
294 {
295     int cssid, ssid, schid, m;
296     SubchDev *sch;
297     uint64_t addr;
298     int cc;
299     SCHIB *schib;
300     hwaddr len = sizeof(*schib);
301     CPUS390XState *env = &cpu->env;
302
303     addr = decode_basedisp_s(env, ipb);
304     if (addr & 3) {
305         program_interrupt(env, PGM_SPECIFICATION, 2);
306         return;
307     }
308     schib = s390_cpu_physical_memory_map(env, addr, &len, 1);
309     if (!schib || len != sizeof(*schib)) {
310         program_interrupt(env, PGM_ADDRESSING, 2);
311         goto out;
312     }
313
314     if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
315         program_interrupt(env, PGM_OPERAND, 2);
316         goto out;
317     }
318     trace_ioinst_sch_id("stsch", cssid, ssid, schid);
319     sch = css_find_subch(m, cssid, ssid, schid);
320     if (sch) {
321         if (css_subch_visible(sch)) {
322             css_do_stsch(sch, schib);
323             cc = 0;
324         } else {
325             /* Indicate no more subchannels in this css/ss */
326             cc = 3;
327         }
328     } else {
329         if (css_schid_final(m, cssid, ssid, schid)) {
330             cc = 3; /* No more subchannels in this css/ss */
331         } else {
332             /* Store an empty schib. */
333             memset(schib, 0, sizeof(*schib));
334             cc = 0;
335         }
336     }
337     setcc(cpu, cc);
338
339 out:
340     s390_cpu_physical_memory_unmap(env, schib, len, 1);
341 }
342
343 int ioinst_handle_tsch(CPUS390XState *env, uint64_t reg1, uint32_t ipb)
344 {
345     int cssid, ssid, schid, m;
346     SubchDev *sch;
347     IRB *irb;
348     uint64_t addr;
349     int ret = -ENODEV;
350     int cc;
351     hwaddr len = sizeof(*irb);
352
353     if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
354         program_interrupt(env, PGM_OPERAND, 2);
355         return -EIO;
356     }
357     trace_ioinst_sch_id("tsch", cssid, ssid, schid);
358     addr = decode_basedisp_s(env, ipb);
359     if (addr & 3) {
360         program_interrupt(env, PGM_SPECIFICATION, 2);
361         return -EIO;
362     }
363     irb = s390_cpu_physical_memory_map(env, addr, &len, 1);
364     if (!irb || len != sizeof(*irb)) {
365         program_interrupt(env, PGM_ADDRESSING, 2);
366         cc = -EIO;
367         goto out;
368     }
369     sch = css_find_subch(m, cssid, ssid, schid);
370     if (sch && css_subch_visible(sch)) {
371         ret = css_do_tsch(sch, irb);
372         /* 0 - status pending, 1 - not status pending */
373         cc = ret;
374     } else {
375         cc = 3;
376     }
377 out:
378     s390_cpu_physical_memory_unmap(env, irb, sizeof(*irb), 1);
379     return cc;
380 }
381
382 typedef struct ChscReq {
383     uint16_t len;
384     uint16_t command;
385     uint32_t param0;
386     uint32_t param1;
387     uint32_t param2;
388 } QEMU_PACKED ChscReq;
389
390 typedef struct ChscResp {
391     uint16_t len;
392     uint16_t code;
393     uint32_t param;
394     char data[0];
395 } QEMU_PACKED ChscResp;
396
397 #define CHSC_MIN_RESP_LEN 0x0008
398
399 #define CHSC_SCPD 0x0002
400 #define CHSC_SCSC 0x0010
401 #define CHSC_SDA  0x0031
402 #define CHSC_SEI  0x000e
403
404 #define CHSC_SCPD_0_M 0x20000000
405 #define CHSC_SCPD_0_C 0x10000000
406 #define CHSC_SCPD_0_FMT 0x0f000000
407 #define CHSC_SCPD_0_CSSID 0x00ff0000
408 #define CHSC_SCPD_0_RFMT 0x00000f00
409 #define CHSC_SCPD_0_RES 0xc000f000
410 #define CHSC_SCPD_1_RES 0xffffff00
411 #define CHSC_SCPD_01_CHPID 0x000000ff
412 static void ioinst_handle_chsc_scpd(ChscReq *req, ChscResp *res)
413 {
414     uint16_t len = be16_to_cpu(req->len);
415     uint32_t param0 = be32_to_cpu(req->param0);
416     uint32_t param1 = be32_to_cpu(req->param1);
417     uint16_t resp_code;
418     int rfmt;
419     uint16_t cssid;
420     uint8_t f_chpid, l_chpid;
421     int desc_size;
422     int m;
423
424     rfmt = (param0 & CHSC_SCPD_0_RFMT) >> 8;
425     if ((rfmt == 0) ||  (rfmt == 1)) {
426         rfmt = !!(param0 & CHSC_SCPD_0_C);
427     }
428     if ((len != 0x0010) || (param0 & CHSC_SCPD_0_RES) ||
429         (param1 & CHSC_SCPD_1_RES) || req->param2) {
430         resp_code = 0x0003;
431         goto out_err;
432     }
433     if (param0 & CHSC_SCPD_0_FMT) {
434         resp_code = 0x0007;
435         goto out_err;
436     }
437     cssid = (param0 & CHSC_SCPD_0_CSSID) >> 16;
438     m = param0 & CHSC_SCPD_0_M;
439     if (cssid != 0) {
440         if (!m || !css_present(cssid)) {
441             resp_code = 0x0008;
442             goto out_err;
443         }
444     }
445     f_chpid = param0 & CHSC_SCPD_01_CHPID;
446     l_chpid = param1 & CHSC_SCPD_01_CHPID;
447     if (l_chpid < f_chpid) {
448         resp_code = 0x0003;
449         goto out_err;
450     }
451     /* css_collect_chp_desc() is endian-aware */
452     desc_size = css_collect_chp_desc(m, cssid, f_chpid, l_chpid, rfmt,
453                                      &res->data);
454     res->code = cpu_to_be16(0x0001);
455     res->len = cpu_to_be16(8 + desc_size);
456     res->param = cpu_to_be32(rfmt);
457     return;
458
459   out_err:
460     res->code = cpu_to_be16(resp_code);
461     res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
462     res->param = cpu_to_be32(rfmt);
463 }
464
465 #define CHSC_SCSC_0_M 0x20000000
466 #define CHSC_SCSC_0_FMT 0x000f0000
467 #define CHSC_SCSC_0_CSSID 0x0000ff00
468 #define CHSC_SCSC_0_RES 0xdff000ff
469 static void ioinst_handle_chsc_scsc(ChscReq *req, ChscResp *res)
470 {
471     uint16_t len = be16_to_cpu(req->len);
472     uint32_t param0 = be32_to_cpu(req->param0);
473     uint8_t cssid;
474     uint16_t resp_code;
475     uint32_t general_chars[510];
476     uint32_t chsc_chars[508];
477
478     if (len != 0x0010) {
479         resp_code = 0x0003;
480         goto out_err;
481     }
482
483     if (param0 & CHSC_SCSC_0_FMT) {
484         resp_code = 0x0007;
485         goto out_err;
486     }
487     cssid = (param0 & CHSC_SCSC_0_CSSID) >> 8;
488     if (cssid != 0) {
489         if (!(param0 & CHSC_SCSC_0_M) || !css_present(cssid)) {
490             resp_code = 0x0008;
491             goto out_err;
492         }
493     }
494     if ((param0 & CHSC_SCSC_0_RES) || req->param1 || req->param2) {
495         resp_code = 0x0003;
496         goto out_err;
497     }
498     res->code = cpu_to_be16(0x0001);
499     res->len = cpu_to_be16(4080);
500     res->param = 0;
501
502     memset(general_chars, 0, sizeof(general_chars));
503     memset(chsc_chars, 0, sizeof(chsc_chars));
504
505     general_chars[0] = cpu_to_be32(0x03000000);
506     general_chars[1] = cpu_to_be32(0x00059000);
507
508     chsc_chars[0] = cpu_to_be32(0x40000000);
509     chsc_chars[3] = cpu_to_be32(0x00040000);
510
511     memcpy(res->data, general_chars, sizeof(general_chars));
512     memcpy(res->data + sizeof(general_chars), chsc_chars, sizeof(chsc_chars));
513     return;
514
515   out_err:
516     res->code = cpu_to_be16(resp_code);
517     res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
518     res->param = 0;
519 }
520
521 #define CHSC_SDA_0_FMT 0x0f000000
522 #define CHSC_SDA_0_OC 0x0000ffff
523 #define CHSC_SDA_0_RES 0xf0ff0000
524 #define CHSC_SDA_OC_MCSSE 0x0
525 #define CHSC_SDA_OC_MSS 0x2
526 static void ioinst_handle_chsc_sda(ChscReq *req, ChscResp *res)
527 {
528     uint16_t resp_code = 0x0001;
529     uint16_t len = be16_to_cpu(req->len);
530     uint32_t param0 = be32_to_cpu(req->param0);
531     uint16_t oc;
532     int ret;
533
534     if ((len != 0x0400) || (param0 & CHSC_SDA_0_RES)) {
535         resp_code = 0x0003;
536         goto out;
537     }
538
539     if (param0 & CHSC_SDA_0_FMT) {
540         resp_code = 0x0007;
541         goto out;
542     }
543
544     oc = param0 & CHSC_SDA_0_OC;
545     switch (oc) {
546     case CHSC_SDA_OC_MCSSE:
547         ret = css_enable_mcsse();
548         if (ret == -EINVAL) {
549             resp_code = 0x0101;
550             goto out;
551         }
552         break;
553     case CHSC_SDA_OC_MSS:
554         ret = css_enable_mss();
555         if (ret == -EINVAL) {
556             resp_code = 0x0101;
557             goto out;
558         }
559         break;
560     default:
561         resp_code = 0x0003;
562         goto out;
563     }
564
565 out:
566     res->code = cpu_to_be16(resp_code);
567     res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
568     res->param = 0;
569 }
570
571 static int chsc_sei_nt0_get_event(void *res)
572 {
573     /* no events yet */
574     return 1;
575 }
576
577 static int chsc_sei_nt0_have_event(void)
578 {
579     /* no events yet */
580     return 0;
581 }
582
583 #define CHSC_SEI_NT0    (1ULL << 63)
584 #define CHSC_SEI_NT2    (1ULL << 61)
585 static void ioinst_handle_chsc_sei(ChscReq *req, ChscResp *res)
586 {
587     uint64_t selection_mask = ldq_p(&req->param1);
588     uint8_t *res_flags = (uint8_t *)res->data;
589     int have_event = 0;
590     int have_more = 0;
591
592     /* regarding architecture nt0 can not be masked */
593     have_event = !chsc_sei_nt0_get_event(res);
594     have_more = chsc_sei_nt0_have_event();
595
596     if (selection_mask & CHSC_SEI_NT2) {
597         if (!have_event) {
598             have_event = !chsc_sei_nt2_get_event(res);
599         }
600
601         if (!have_more) {
602             have_more = chsc_sei_nt2_have_event();
603         }
604     }
605
606     if (have_event) {
607         res->code = cpu_to_be16(0x0001);
608         if (have_more) {
609             (*res_flags) |= 0x80;
610         } else {
611             (*res_flags) &= ~0x80;
612         }
613     } else {
614         res->code = cpu_to_be16(0x0004);
615     }
616 }
617
618 static void ioinst_handle_chsc_unimplemented(ChscResp *res)
619 {
620     res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
621     res->code = cpu_to_be16(0x0004);
622     res->param = 0;
623 }
624
625 void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb)
626 {
627     ChscReq *req;
628     ChscResp *res;
629     uint64_t addr;
630     int reg;
631     uint16_t len;
632     uint16_t command;
633     hwaddr map_size = TARGET_PAGE_SIZE;
634     CPUS390XState *env = &cpu->env;
635
636     trace_ioinst("chsc");
637     reg = (ipb >> 20) & 0x00f;
638     addr = env->regs[reg];
639     /* Page boundary? */
640     if (addr & 0xfff) {
641         program_interrupt(env, PGM_SPECIFICATION, 2);
642         return;
643     }
644     req = s390_cpu_physical_memory_map(env, addr, &map_size, 1);
645     if (!req || map_size != TARGET_PAGE_SIZE) {
646         program_interrupt(env, PGM_ADDRESSING, 2);
647         goto out;
648     }
649     len = be16_to_cpu(req->len);
650     /* Length field valid? */
651     if ((len < 16) || (len > 4088) || (len & 7)) {
652         program_interrupt(env, PGM_OPERAND, 2);
653         goto out;
654     }
655     memset((char *)req + len, 0, TARGET_PAGE_SIZE - len);
656     res = (void *)((char *)req + len);
657     command = be16_to_cpu(req->command);
658     trace_ioinst_chsc_cmd(command, len);
659     switch (command) {
660     case CHSC_SCSC:
661         ioinst_handle_chsc_scsc(req, res);
662         break;
663     case CHSC_SCPD:
664         ioinst_handle_chsc_scpd(req, res);
665         break;
666     case CHSC_SDA:
667         ioinst_handle_chsc_sda(req, res);
668         break;
669     case CHSC_SEI:
670         ioinst_handle_chsc_sei(req, res);
671         break;
672     default:
673         ioinst_handle_chsc_unimplemented(res);
674         break;
675     }
676
677     setcc(cpu, 0);    /* Command execution complete */
678 out:
679     s390_cpu_physical_memory_unmap(env, req, map_size, 1);
680 }
681
682 int ioinst_handle_tpi(CPUS390XState *env, uint32_t ipb)
683 {
684     uint64_t addr;
685     int lowcore;
686     IOIntCode *int_code;
687     hwaddr len, orig_len;
688     int ret;
689
690     trace_ioinst("tpi");
691     addr = decode_basedisp_s(env, ipb);
692     if (addr & 3) {
693         program_interrupt(env, PGM_SPECIFICATION, 2);
694         return -EIO;
695     }
696
697     lowcore = addr ? 0 : 1;
698     len = lowcore ? 8 /* two words */ : 12 /* three words */;
699     orig_len = len;
700     int_code = s390_cpu_physical_memory_map(env, addr, &len, 1);
701     if (!int_code || (len != orig_len)) {
702         program_interrupt(env, PGM_ADDRESSING, 2);
703         ret = -EIO;
704         goto out;
705     }
706     ret = css_do_tpi(int_code, lowcore);
707 out:
708     s390_cpu_physical_memory_unmap(env, int_code, len, 1);
709     return ret;
710 }
711
712 #define SCHM_REG1_RES(_reg) (_reg & 0x000000000ffffffc)
713 #define SCHM_REG1_MBK(_reg) ((_reg & 0x00000000f0000000) >> 28)
714 #define SCHM_REG1_UPD(_reg) ((_reg & 0x0000000000000002) >> 1)
715 #define SCHM_REG1_DCT(_reg) (_reg & 0x0000000000000001)
716
717 void ioinst_handle_schm(S390CPU *cpu, uint64_t reg1, uint64_t reg2,
718                         uint32_t ipb)
719 {
720     uint8_t mbk;
721     int update;
722     int dct;
723     CPUS390XState *env = &cpu->env;
724
725     trace_ioinst("schm");
726
727     if (SCHM_REG1_RES(reg1)) {
728         program_interrupt(env, PGM_OPERAND, 2);
729         return;
730     }
731
732     mbk = SCHM_REG1_MBK(reg1);
733     update = SCHM_REG1_UPD(reg1);
734     dct = SCHM_REG1_DCT(reg1);
735
736     if (update && (reg2 & 0x000000000000001f)) {
737         program_interrupt(env, PGM_OPERAND, 2);
738         return;
739     }
740
741     css_do_schm(mbk, update, dct, update ? reg2 : 0);
742 }
743
744 void ioinst_handle_rsch(S390CPU *cpu, uint64_t reg1)
745 {
746     int cssid, ssid, schid, m;
747     SubchDev *sch;
748     int ret = -ENODEV;
749     int cc;
750
751     if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
752         program_interrupt(&cpu->env, PGM_OPERAND, 2);
753         return;
754     }
755     trace_ioinst_sch_id("rsch", cssid, ssid, schid);
756     sch = css_find_subch(m, cssid, ssid, schid);
757     if (sch && css_subch_visible(sch)) {
758         ret = css_do_rsch(sch);
759     }
760     switch (ret) {
761     case -ENODEV:
762         cc = 3;
763         break;
764     case -EINVAL:
765         cc = 2;
766         break;
767     case 0:
768         cc = 0;
769         break;
770     default:
771         cc = 1;
772         break;
773     }
774     setcc(cpu, cc);
775 }
776
777 #define RCHP_REG1_RES(_reg) (_reg & 0x00000000ff00ff00)
778 #define RCHP_REG1_CSSID(_reg) ((_reg & 0x0000000000ff0000) >> 16)
779 #define RCHP_REG1_CHPID(_reg) (_reg & 0x00000000000000ff)
780 void ioinst_handle_rchp(S390CPU *cpu, uint64_t reg1)
781 {
782     int cc;
783     uint8_t cssid;
784     uint8_t chpid;
785     int ret;
786     CPUS390XState *env = &cpu->env;
787
788     if (RCHP_REG1_RES(reg1)) {
789         program_interrupt(env, PGM_OPERAND, 2);
790         return;
791     }
792
793     cssid = RCHP_REG1_CSSID(reg1);
794     chpid = RCHP_REG1_CHPID(reg1);
795
796     trace_ioinst_chp_id("rchp", cssid, chpid);
797
798     ret = css_do_rchp(cssid, chpid);
799
800     switch (ret) {
801     case -ENODEV:
802         cc = 3;
803         break;
804     case -EBUSY:
805         cc = 2;
806         break;
807     case 0:
808         cc = 0;
809         break;
810     default:
811         /* Invalid channel subsystem. */
812         program_interrupt(env, PGM_OPERAND, 2);
813         return;
814     }
815     setcc(cpu, cc);
816 }
817
818 #define SAL_REG1_INVALID(_reg) (_reg & 0x0000000080000000)
819 void ioinst_handle_sal(S390CPU *cpu, uint64_t reg1)
820 {
821     /* We do not provide address limit checking, so let's suppress it. */
822     if (SAL_REG1_INVALID(reg1) || reg1 & 0x000000000000ffff) {
823         program_interrupt(&cpu->env, PGM_OPERAND, 2);
824     }
825 }
This page took 0.067534 seconds and 4 git commands to generate.