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