~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to target/s390x/ioinst.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

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