]> Git Repo - qemu.git/blame - hw/s390x/s390-pci-inst.c
s390x/pci: enable uid-checking
[qemu.git] / hw / s390x / s390-pci-inst.c
CommitLineData
863f6f52
FB
1/*
2 * s390 PCI instructions
3 *
4 * Copyright 2014 IBM Corp.
5 * Author(s): Frank Blaschka <[email protected]>
6 * Hong Bo Li <[email protected]>
7 * Yi Min Zhao <[email protected]>
8 *
9 * This work is licensed under the terms of the GNU GPL, version 2 or (at
10 * your option) any later version. See the COPYING file in the top-level
11 * directory.
12 */
13
9615495a 14#include "qemu/osdep.h"
4771d756
PB
15#include "qemu-common.h"
16#include "cpu.h"
863f6f52
FB
17#include "s390-pci-inst.h"
18#include "s390-pci-bus.h"
19#include <exec/memory-internal.h>
20#include <qemu/error-report.h>
21
22/* #define DEBUG_S390PCI_INST */
23#ifdef DEBUG_S390PCI_INST
24#define DPRINTF(fmt, ...) \
25 do { fprintf(stderr, "s390pci-inst: " fmt, ## __VA_ARGS__); } while (0)
26#else
27#define DPRINTF(fmt, ...) \
28 do { } while (0)
29#endif
30
31static void s390_set_status_code(CPUS390XState *env,
32 uint8_t r, uint64_t status_code)
33{
34 env->regs[r] &= ~0xff000000ULL;
35 env->regs[r] |= (status_code & 0xff) << 24;
36}
37
38static int list_pci(ClpReqRspListPci *rrb, uint8_t *cc)
39{
40 S390PCIBusDevice *pbdev;
41 uint32_t res_code, initial_l2, g_l2, finish;
42 int rc, idx;
43 uint64_t resume_token;
44
45 rc = 0;
46 if (lduw_p(&rrb->request.hdr.len) != 32) {
47 res_code = CLP_RC_LEN;
48 rc = -EINVAL;
49 goto out;
50 }
51
52 if ((ldl_p(&rrb->request.fmt) & CLP_MASK_FMT) != 0) {
53 res_code = CLP_RC_FMT;
54 rc = -EINVAL;
55 goto out;
56 }
57
58 if ((ldl_p(&rrb->request.fmt) & ~CLP_MASK_FMT) != 0 ||
bf328399 59 ldq_p(&rrb->request.reserved1) != 0) {
863f6f52
FB
60 res_code = CLP_RC_RESNOT0;
61 rc = -EINVAL;
62 goto out;
63 }
64
65 resume_token = ldq_p(&rrb->request.resume_token);
66
67 if (resume_token) {
68 pbdev = s390_pci_find_dev_by_idx(resume_token);
69 if (!pbdev) {
70 res_code = CLP_RC_LISTPCI_BADRT;
71 rc = -EINVAL;
72 goto out;
73 }
74 }
75
76 if (lduw_p(&rrb->response.hdr.len) < 48) {
77 res_code = CLP_RC_8K;
78 rc = -EINVAL;
79 goto out;
80 }
81
82 initial_l2 = lduw_p(&rrb->response.hdr.len);
83 if ((initial_l2 - LIST_PCI_HDR_LEN) % sizeof(ClpFhListEntry)
84 != 0) {
85 res_code = CLP_RC_LEN;
86 rc = -EINVAL;
87 *cc = 3;
88 goto out;
89 }
90
91 stl_p(&rrb->response.fmt, 0);
92 stq_p(&rrb->response.reserved1, 0);
c188e303 93 stl_p(&rrb->response.mdd, FH_MASK_SHM);
863f6f52 94 stw_p(&rrb->response.max_fn, PCI_MAX_FUNCTIONS);
bf328399 95 rrb->response.flags = UID_CHECKING_ENABLED;
863f6f52
FB
96 rrb->response.entry_size = sizeof(ClpFhListEntry);
97 finish = 0;
98 idx = resume_token;
99 g_l2 = LIST_PCI_HDR_LEN;
100 do {
101 pbdev = s390_pci_find_dev_by_idx(idx);
102 if (!pbdev) {
103 finish = 1;
104 break;
105 }
106 stw_p(&rrb->response.fh_list[idx - resume_token].device_id,
107 pci_get_word(pbdev->pdev->config + PCI_DEVICE_ID));
108 stw_p(&rrb->response.fh_list[idx - resume_token].vendor_id,
109 pci_get_word(pbdev->pdev->config + PCI_VENDOR_ID));
5d1abf23 110 /* Ignore RESERVED devices. */
88bfa216 111 stl_p(&rrb->response.fh_list[idx - resume_token].config,
5d1abf23 112 pbdev->state == ZPCI_FS_STANDBY ? 0 : 1 << 31);
863f6f52
FB
113 stl_p(&rrb->response.fh_list[idx - resume_token].fid, pbdev->fid);
114 stl_p(&rrb->response.fh_list[idx - resume_token].fh, pbdev->fh);
115
116 g_l2 += sizeof(ClpFhListEntry);
117 /* Add endian check for DPRINTF? */
118 DPRINTF("g_l2 %d vendor id 0x%x device id 0x%x fid 0x%x fh 0x%x\n",
119 g_l2,
120 lduw_p(&rrb->response.fh_list[idx - resume_token].vendor_id),
121 lduw_p(&rrb->response.fh_list[idx - resume_token].device_id),
122 ldl_p(&rrb->response.fh_list[idx - resume_token].fid),
123 ldl_p(&rrb->response.fh_list[idx - resume_token].fh));
124 idx++;
125 } while (g_l2 < initial_l2);
126
127 if (finish == 1) {
128 resume_token = 0;
129 } else {
130 resume_token = idx;
131 }
132 stq_p(&rrb->response.resume_token, resume_token);
133 stw_p(&rrb->response.hdr.len, g_l2);
134 stw_p(&rrb->response.hdr.rsp, CLP_RC_OK);
135out:
136 if (rc) {
137 DPRINTF("list pci failed rc 0x%x\n", rc);
138 stw_p(&rrb->response.hdr.rsp, res_code);
139 }
140 return rc;
141}
142
143int clp_service_call(S390CPU *cpu, uint8_t r2)
144{
145 ClpReqHdr *reqh;
146 ClpRspHdr *resh;
147 S390PCIBusDevice *pbdev;
148 uint32_t req_len;
149 uint32_t res_len;
150 uint8_t buffer[4096 * 2];
151 uint8_t cc = 0;
152 CPUS390XState *env = &cpu->env;
153 int i;
154
155 cpu_synchronize_state(CPU(cpu));
156
157 if (env->psw.mask & PSW_MASK_PSTATE) {
158 program_interrupt(env, PGM_PRIVILEGED, 4);
159 return 0;
160 }
161
6cb1e49d 162 if (s390_cpu_virt_mem_read(cpu, env->regs[r2], r2, buffer, sizeof(*reqh))) {
63ceef61
FB
163 return 0;
164 }
863f6f52
FB
165 reqh = (ClpReqHdr *)buffer;
166 req_len = lduw_p(&reqh->len);
167 if (req_len < 16 || req_len > 8184 || (req_len % 8 != 0)) {
168 program_interrupt(env, PGM_OPERAND, 4);
169 return 0;
170 }
171
6cb1e49d 172 if (s390_cpu_virt_mem_read(cpu, env->regs[r2], r2, buffer,
63ceef61
FB
173 req_len + sizeof(*resh))) {
174 return 0;
175 }
863f6f52
FB
176 resh = (ClpRspHdr *)(buffer + req_len);
177 res_len = lduw_p(&resh->len);
178 if (res_len < 8 || res_len > 8176 || (res_len % 8 != 0)) {
179 program_interrupt(env, PGM_OPERAND, 4);
180 return 0;
181 }
182 if ((req_len + res_len) > 8192) {
183 program_interrupt(env, PGM_OPERAND, 4);
184 return 0;
185 }
186
6cb1e49d 187 if (s390_cpu_virt_mem_read(cpu, env->regs[r2], r2, buffer,
63ceef61
FB
188 req_len + res_len)) {
189 return 0;
190 }
863f6f52
FB
191
192 if (req_len != 32) {
193 stw_p(&resh->rsp, CLP_RC_LEN);
194 goto out;
195 }
196
197 switch (lduw_p(&reqh->cmd)) {
198 case CLP_LIST_PCI: {
199 ClpReqRspListPci *rrb = (ClpReqRspListPci *)buffer;
200 list_pci(rrb, &cc);
201 break;
202 }
203 case CLP_SET_PCI_FN: {
204 ClpReqSetPci *reqsetpci = (ClpReqSetPci *)reqh;
205 ClpRspSetPci *ressetpci = (ClpRspSetPci *)resh;
206
207 pbdev = s390_pci_find_dev_by_fh(ldl_p(&reqsetpci->fh));
208 if (!pbdev) {
209 stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FH);
210 goto out;
211 }
212
213 switch (reqsetpci->oc) {
214 case CLP_SET_ENABLE_PCI_FN:
c188e303 215 pbdev->fh |= FH_MASK_ENABLE;
5d1abf23 216 pbdev->state = ZPCI_FS_ENABLED;
863f6f52
FB
217 stl_p(&ressetpci->fh, pbdev->fh);
218 stw_p(&ressetpci->hdr.rsp, CLP_RC_OK);
219 break;
220 case CLP_SET_DISABLE_PCI_FN:
c188e303 221 pbdev->fh &= ~FH_MASK_ENABLE;
5d1abf23 222 pbdev->state = ZPCI_FS_DISABLED;
863f6f52
FB
223 stl_p(&ressetpci->fh, pbdev->fh);
224 stw_p(&ressetpci->hdr.rsp, CLP_RC_OK);
225 break;
226 default:
227 DPRINTF("unknown set pci command\n");
228 stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FHOP);
229 break;
230 }
231 break;
232 }
233 case CLP_QUERY_PCI_FN: {
234 ClpReqQueryPci *reqquery = (ClpReqQueryPci *)reqh;
235 ClpRspQueryPci *resquery = (ClpRspQueryPci *)resh;
236
237 pbdev = s390_pci_find_dev_by_fh(ldl_p(&reqquery->fh));
238 if (!pbdev) {
239 DPRINTF("query pci no pci dev\n");
240 stw_p(&resquery->hdr.rsp, CLP_RC_SETPCIFN_FH);
241 goto out;
242 }
243
244 for (i = 0; i < PCI_BAR_COUNT; i++) {
245 uint32_t data = pci_get_long(pbdev->pdev->config +
246 PCI_BASE_ADDRESS_0 + (i * 4));
247
248 stl_p(&resquery->bar[i], data);
249 resquery->bar_size[i] = pbdev->pdev->io_regions[i].size ?
250 ctz64(pbdev->pdev->io_regions[i].size) : 0;
251 DPRINTF("bar %d addr 0x%x size 0x%" PRIx64 "barsize 0x%x\n", i,
252 ldl_p(&resquery->bar[i]),
253 pbdev->pdev->io_regions[i].size,
254 resquery->bar_size[i]);
255 }
256
257 stq_p(&resquery->sdma, ZPCI_SDMA_ADDR);
258 stq_p(&resquery->edma, ZPCI_EDMA_ADDR);
67aad508 259 stl_p(&resquery->fid, pbdev->fid);
863f6f52
FB
260 stw_p(&resquery->pchid, 0);
261 stw_p(&resquery->ug, 1);
bf328399 262 stl_p(&resquery->uid, pbdev->uid);
863f6f52
FB
263 stw_p(&resquery->hdr.rsp, CLP_RC_OK);
264 break;
265 }
266 case CLP_QUERY_PCI_FNGRP: {
267 ClpRspQueryPciGrp *resgrp = (ClpRspQueryPciGrp *)resh;
268 resgrp->fr = 1;
269 stq_p(&resgrp->dasm, 0);
270 stq_p(&resgrp->msia, ZPCI_MSI_ADDR);
271 stw_p(&resgrp->mui, 0);
272 stw_p(&resgrp->i, 128);
273 resgrp->version = 0;
274
275 stw_p(&resgrp->hdr.rsp, CLP_RC_OK);
276 break;
277 }
278 default:
279 DPRINTF("unknown clp command\n");
280 stw_p(&resh->rsp, CLP_RC_CMD);
281 break;
282 }
283
284out:
6cb1e49d 285 if (s390_cpu_virt_mem_write(cpu, env->regs[r2], r2, buffer,
63ceef61
FB
286 req_len + res_len)) {
287 return 0;
288 }
863f6f52
FB
289 setcc(cpu, cc);
290 return 0;
291}
292
293int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
294{
295 CPUS390XState *env = &cpu->env;
296 S390PCIBusDevice *pbdev;
297 uint64_t offset;
298 uint64_t data;
299 uint8_t len;
300 uint32_t fh;
301 uint8_t pcias;
302
303 cpu_synchronize_state(CPU(cpu));
304
305 if (env->psw.mask & PSW_MASK_PSTATE) {
306 program_interrupt(env, PGM_PRIVILEGED, 4);
307 return 0;
308 }
309
310 if (r2 & 0x1) {
311 program_interrupt(env, PGM_SPECIFICATION, 4);
312 return 0;
313 }
314
315 fh = env->regs[r2] >> 32;
316 pcias = (env->regs[r2] >> 16) & 0xf;
317 len = env->regs[r2] & 0xf;
318 offset = env->regs[r2 + 1];
319
320 pbdev = s390_pci_find_dev_by_fh(fh);
5d1abf23 321 if (!pbdev) {
863f6f52
FB
322 DPRINTF("pcilg no pci dev\n");
323 setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
324 return 0;
325 }
326
5d1abf23
YMZ
327 switch (pbdev->state) {
328 case ZPCI_FS_RESERVED:
329 case ZPCI_FS_STANDBY:
330 case ZPCI_FS_DISABLED:
331 case ZPCI_FS_PERMANENT_ERROR:
332 setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
333 return 0;
334 case ZPCI_FS_ERROR:
863f6f52
FB
335 setcc(cpu, ZPCI_PCI_LS_ERR);
336 s390_set_status_code(env, r2, ZPCI_PCI_ST_BLOCKED);
337 return 0;
5d1abf23
YMZ
338 default:
339 break;
863f6f52
FB
340 }
341
342 if (pcias < 6) {
343 if ((8 - (offset & 0x7)) < len) {
344 program_interrupt(env, PGM_OPERAND, 4);
345 return 0;
346 }
347 MemoryRegion *mr = pbdev->pdev->io_regions[pcias].memory;
3b643495
PM
348 memory_region_dispatch_read(mr, offset, &data, len,
349 MEMTXATTRS_UNSPECIFIED);
863f6f52
FB
350 } else if (pcias == 15) {
351 if ((4 - (offset & 0x3)) < len) {
352 program_interrupt(env, PGM_OPERAND, 4);
353 return 0;
354 }
355 data = pci_host_config_read_common(
356 pbdev->pdev, offset, pci_config_size(pbdev->pdev), len);
357
358 switch (len) {
359 case 1:
360 break;
361 case 2:
362 data = bswap16(data);
363 break;
364 case 4:
365 data = bswap32(data);
366 break;
367 case 8:
368 data = bswap64(data);
369 break;
370 default:
371 program_interrupt(env, PGM_OPERAND, 4);
372 return 0;
373 }
374 } else {
375 DPRINTF("invalid space\n");
376 setcc(cpu, ZPCI_PCI_LS_ERR);
377 s390_set_status_code(env, r2, ZPCI_PCI_ST_INVAL_AS);
378 return 0;
379 }
380
381 env->regs[r1] = data;
382 setcc(cpu, ZPCI_PCI_LS_OK);
383 return 0;
384}
385
386static void update_msix_table_msg_data(S390PCIBusDevice *pbdev, uint64_t offset,
387 uint64_t *data, uint8_t len)
388{
389 uint32_t val;
390 uint8_t *msg_data;
391
392 if (offset % PCI_MSIX_ENTRY_SIZE != 8) {
393 return;
394 }
395
396 if (len != 4) {
397 DPRINTF("access msix table msg data but len is %d\n", len);
398 return;
399 }
400
401 msg_data = (uint8_t *)data - offset % PCI_MSIX_ENTRY_SIZE +
402 PCI_MSIX_ENTRY_VECTOR_CTRL;
403 val = pci_get_long(msg_data) | (pbdev->fid << ZPCI_MSI_VEC_BITS);
404 pci_set_long(msg_data, val);
405 DPRINTF("update msix msg_data to 0x%" PRIx64 "\n", *data);
406}
407
408static int trap_msix(S390PCIBusDevice *pbdev, uint64_t offset, uint8_t pcias)
409{
410 if (pbdev->msix.available && pbdev->msix.table_bar == pcias &&
411 offset >= pbdev->msix.table_offset &&
412 offset <= pbdev->msix.table_offset +
413 (pbdev->msix.entries - 1) * PCI_MSIX_ENTRY_SIZE) {
414 return 1;
415 } else {
416 return 0;
417 }
418}
419
420int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
421{
422 CPUS390XState *env = &cpu->env;
423 uint64_t offset, data;
424 S390PCIBusDevice *pbdev;
425 uint8_t len;
426 uint32_t fh;
427 uint8_t pcias;
428
429 cpu_synchronize_state(CPU(cpu));
430
431 if (env->psw.mask & PSW_MASK_PSTATE) {
432 program_interrupt(env, PGM_PRIVILEGED, 4);
433 return 0;
434 }
435
436 if (r2 & 0x1) {
437 program_interrupt(env, PGM_SPECIFICATION, 4);
438 return 0;
439 }
440
441 fh = env->regs[r2] >> 32;
442 pcias = (env->regs[r2] >> 16) & 0xf;
443 len = env->regs[r2] & 0xf;
444 offset = env->regs[r2 + 1];
445
446 pbdev = s390_pci_find_dev_by_fh(fh);
5d1abf23 447 if (!pbdev) {
863f6f52
FB
448 DPRINTF("pcistg no pci dev\n");
449 setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
450 return 0;
451 }
452
5d1abf23
YMZ
453 switch (pbdev->state) {
454 case ZPCI_FS_RESERVED:
455 case ZPCI_FS_STANDBY:
456 case ZPCI_FS_DISABLED:
457 case ZPCI_FS_PERMANENT_ERROR:
458 setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
459 return 0;
460 case ZPCI_FS_ERROR:
863f6f52
FB
461 setcc(cpu, ZPCI_PCI_LS_ERR);
462 s390_set_status_code(env, r2, ZPCI_PCI_ST_BLOCKED);
463 return 0;
5d1abf23
YMZ
464 default:
465 break;
863f6f52
FB
466 }
467
468 data = env->regs[r1];
469 if (pcias < 6) {
470 if ((8 - (offset & 0x7)) < len) {
471 program_interrupt(env, PGM_OPERAND, 4);
472 return 0;
473 }
474 MemoryRegion *mr;
475 if (trap_msix(pbdev, offset, pcias)) {
476 offset = offset - pbdev->msix.table_offset;
477 mr = &pbdev->pdev->msix_table_mmio;
478 update_msix_table_msg_data(pbdev, offset, &data, len);
479 } else {
480 mr = pbdev->pdev->io_regions[pcias].memory;
481 }
482
3b643495
PM
483 memory_region_dispatch_write(mr, offset, data, len,
484 MEMTXATTRS_UNSPECIFIED);
863f6f52
FB
485 } else if (pcias == 15) {
486 if ((4 - (offset & 0x3)) < len) {
487 program_interrupt(env, PGM_OPERAND, 4);
488 return 0;
489 }
490 switch (len) {
491 case 1:
492 break;
493 case 2:
494 data = bswap16(data);
495 break;
496 case 4:
497 data = bswap32(data);
498 break;
499 case 8:
500 data = bswap64(data);
501 break;
502 default:
503 program_interrupt(env, PGM_OPERAND, 4);
504 return 0;
505 }
506
507 pci_host_config_write_common(pbdev->pdev, offset,
508 pci_config_size(pbdev->pdev),
509 data, len);
510 } else {
511 DPRINTF("pcistg invalid space\n");
512 setcc(cpu, ZPCI_PCI_LS_ERR);
513 s390_set_status_code(env, r2, ZPCI_PCI_ST_INVAL_AS);
514 return 0;
515 }
516
517 setcc(cpu, ZPCI_PCI_LS_OK);
518 return 0;
519}
520
521int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
522{
523 CPUS390XState *env = &cpu->env;
524 uint32_t fh;
525 S390PCIBusDevice *pbdev;
4e99a0f7 526 hwaddr start, end;
863f6f52
FB
527 IOMMUTLBEntry entry;
528 MemoryRegion *mr;
529
530 cpu_synchronize_state(CPU(cpu));
531
532 if (env->psw.mask & PSW_MASK_PSTATE) {
533 program_interrupt(env, PGM_PRIVILEGED, 4);
534 goto out;
535 }
536
537 if (r2 & 0x1) {
538 program_interrupt(env, PGM_SPECIFICATION, 4);
539 goto out;
540 }
541
542 fh = env->regs[r1] >> 32;
4e99a0f7
YMZ
543 start = env->regs[r2];
544 end = start + env->regs[r2 + 1];
863f6f52
FB
545
546 pbdev = s390_pci_find_dev_by_fh(fh);
5d1abf23 547 if (!pbdev) {
863f6f52
FB
548 DPRINTF("rpcit no pci dev\n");
549 setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
550 goto out;
551 }
552
5d1abf23
YMZ
553 switch (pbdev->state) {
554 case ZPCI_FS_RESERVED:
555 case ZPCI_FS_STANDBY:
556 case ZPCI_FS_DISABLED:
557 case ZPCI_FS_PERMANENT_ERROR:
558 setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
559 return 0;
560 case ZPCI_FS_ERROR:
561 setcc(cpu, ZPCI_PCI_LS_ERR);
562 s390_set_status_code(env, r1, ZPCI_MOD_ST_ERROR_RECOVER);
563 return 0;
564 default:
565 break;
566 }
567
568 if (!pbdev->g_iota) {
569 pbdev->state = ZPCI_FS_ERROR;
570 setcc(cpu, ZPCI_PCI_LS_ERR);
571 s390_set_status_code(env, r1, ZPCI_PCI_ST_INSUF_RES);
572 s390_pci_generate_error_event(ERR_EVENT_INVALAS, pbdev->fh, pbdev->fid,
573 start, 0);
574 goto out;
575 }
576
577 if (end < pbdev->pba || start > pbdev->pal) {
578 pbdev->state = ZPCI_FS_ERROR;
579 setcc(cpu, ZPCI_PCI_LS_ERR);
580 s390_set_status_code(env, r1, ZPCI_PCI_ST_INSUF_RES);
581 s390_pci_generate_error_event(ERR_EVENT_OORANGE, pbdev->fh, pbdev->fid,
582 start, 0);
583 goto out;
584 }
585
f0a399db 586 mr = &pbdev->iommu_mr;
4e99a0f7
YMZ
587 while (start < end) {
588 entry = mr->iommu_ops->translate(mr, start, 0);
863f6f52 589
4e99a0f7 590 if (!entry.translated_addr) {
5d1abf23 591 pbdev->state = ZPCI_FS_ERROR;
4e99a0f7 592 setcc(cpu, ZPCI_PCI_LS_ERR);
5d1abf23
YMZ
593 s390_set_status_code(env, r1, ZPCI_PCI_ST_INSUF_RES);
594 s390_pci_generate_error_event(ERR_EVENT_SERR, pbdev->fh, pbdev->fid,
595 start, ERR_EVENT_Q_BIT);
4e99a0f7
YMZ
596 goto out;
597 }
598
599 memory_region_notify_iommu(mr, entry);
600 start += entry.addr_mask + 1;
863f6f52
FB
601 }
602
863f6f52
FB
603 setcc(cpu, ZPCI_PCI_LS_OK);
604out:
605 return 0;
606}
607
6cb1e49d
AY
608int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr,
609 uint8_t ar)
863f6f52
FB
610{
611 CPUS390XState *env = &cpu->env;
612 S390PCIBusDevice *pbdev;
613 MemoryRegion *mr;
614 int i;
863f6f52
FB
615 uint32_t fh;
616 uint8_t pcias;
617 uint8_t len;
63ceef61 618 uint8_t buffer[128];
863f6f52
FB
619
620 if (env->psw.mask & PSW_MASK_PSTATE) {
621 program_interrupt(env, PGM_PRIVILEGED, 6);
622 return 0;
623 }
624
625 fh = env->regs[r1] >> 32;
626 pcias = (env->regs[r1] >> 16) & 0xf;
627 len = env->regs[r1] & 0xff;
628
629 if (pcias > 5) {
630 DPRINTF("pcistb invalid space\n");
631 setcc(cpu, ZPCI_PCI_LS_ERR);
632 s390_set_status_code(env, r1, ZPCI_PCI_ST_INVAL_AS);
633 return 0;
634 }
635
636 switch (len) {
637 case 16:
638 case 32:
639 case 64:
640 case 128:
641 break;
642 default:
643 program_interrupt(env, PGM_SPECIFICATION, 6);
644 return 0;
645 }
646
647 pbdev = s390_pci_find_dev_by_fh(fh);
5d1abf23 648 if (!pbdev) {
863f6f52
FB
649 DPRINTF("pcistb no pci dev fh 0x%x\n", fh);
650 setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
651 return 0;
652 }
653
5d1abf23
YMZ
654 switch (pbdev->state) {
655 case ZPCI_FS_RESERVED:
656 case ZPCI_FS_STANDBY:
657 case ZPCI_FS_DISABLED:
658 case ZPCI_FS_PERMANENT_ERROR:
659 setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
660 return 0;
661 case ZPCI_FS_ERROR:
863f6f52
FB
662 setcc(cpu, ZPCI_PCI_LS_ERR);
663 s390_set_status_code(env, r1, ZPCI_PCI_ST_BLOCKED);
664 return 0;
5d1abf23
YMZ
665 default:
666 break;
863f6f52
FB
667 }
668
669 mr = pbdev->pdev->io_regions[pcias].memory;
670 if (!memory_region_access_valid(mr, env->regs[r3], len, true)) {
671 program_interrupt(env, PGM_ADDRESSING, 6);
672 return 0;
673 }
674
6cb1e49d 675 if (s390_cpu_virt_mem_read(cpu, gaddr, ar, buffer, len)) {
63ceef61
FB
676 return 0;
677 }
678
863f6f52 679 for (i = 0; i < len / 8; i++) {
3b643495
PM
680 memory_region_dispatch_write(mr, env->regs[r3] + i * 8,
681 ldq_p(buffer + i * 8), 8,
682 MEMTXATTRS_UNSPECIFIED);
863f6f52
FB
683 }
684
685 setcc(cpu, ZPCI_PCI_LS_OK);
686 return 0;
687}
688
689static int reg_irqs(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib)
690{
8581c115 691 int ret, len;
863f6f52
FB
692
693 ret = css_register_io_adapter(S390_PCIPT_ADAPTER,
694 FIB_DATA_ISC(ldl_p(&fib.data)), true, false,
695 &pbdev->routes.adapter.adapter_id);
696 assert(ret == 0);
697
8581c115
YMZ
698 pbdev->summary_ind = get_indicator(ldq_p(&fib.aisb), sizeof(uint64_t));
699 len = BITS_TO_LONGS(FIB_DATA_NOI(ldl_p(&fib.data))) * sizeof(unsigned long);
700 pbdev->indicator = get_indicator(ldq_p(&fib.aibv), len);
701
bac45d51
YMZ
702 ret = map_indicator(&pbdev->routes.adapter, pbdev->summary_ind);
703 if (ret) {
704 goto out;
705 }
706
707 ret = map_indicator(&pbdev->routes.adapter, pbdev->indicator);
708 if (ret) {
709 goto out;
710 }
863f6f52
FB
711
712 pbdev->routes.adapter.summary_addr = ldq_p(&fib.aisb);
713 pbdev->routes.adapter.summary_offset = FIB_DATA_AISBO(ldl_p(&fib.data));
714 pbdev->routes.adapter.ind_addr = ldq_p(&fib.aibv);
715 pbdev->routes.adapter.ind_offset = FIB_DATA_AIBVO(ldl_p(&fib.data));
716 pbdev->isc = FIB_DATA_ISC(ldl_p(&fib.data));
717 pbdev->noi = FIB_DATA_NOI(ldl_p(&fib.data));
718 pbdev->sum = FIB_DATA_SUM(ldl_p(&fib.data));
719
720 DPRINTF("reg_irqs adapter id %d\n", pbdev->routes.adapter.adapter_id);
721 return 0;
bac45d51
YMZ
722out:
723 release_indicator(&pbdev->routes.adapter, pbdev->summary_ind);
724 release_indicator(&pbdev->routes.adapter, pbdev->indicator);
725 pbdev->summary_ind = NULL;
726 pbdev->indicator = NULL;
727 return ret;
863f6f52
FB
728}
729
e141dbad 730int pci_dereg_irqs(S390PCIBusDevice *pbdev)
863f6f52 731{
8581c115
YMZ
732 release_indicator(&pbdev->routes.adapter, pbdev->summary_ind);
733 release_indicator(&pbdev->routes.adapter, pbdev->indicator);
863f6f52 734
8581c115
YMZ
735 pbdev->summary_ind = NULL;
736 pbdev->indicator = NULL;
863f6f52
FB
737 pbdev->routes.adapter.summary_addr = 0;
738 pbdev->routes.adapter.summary_offset = 0;
739 pbdev->routes.adapter.ind_addr = 0;
740 pbdev->routes.adapter.ind_offset = 0;
741 pbdev->isc = 0;
742 pbdev->noi = 0;
743 pbdev->sum = 0;
744
745 DPRINTF("dereg_irqs adapter id %d\n", pbdev->routes.adapter.adapter_id);
746 return 0;
747}
748
749static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib)
750{
751 uint64_t pba = ldq_p(&fib.pba);
752 uint64_t pal = ldq_p(&fib.pal);
753 uint64_t g_iota = ldq_p(&fib.iota);
754 uint8_t dt = (g_iota >> 2) & 0x7;
755 uint8_t t = (g_iota >> 11) & 0x1;
756
757 if (pba > pal || pba < ZPCI_SDMA_ADDR || pal > ZPCI_EDMA_ADDR) {
758 program_interrupt(env, PGM_OPERAND, 6);
759 return -EINVAL;
760 }
761
762 /* currently we only support designation type 1 with translation */
763 if (!(dt == ZPCI_IOTA_RTTO && t)) {
764 error_report("unsupported ioat dt %d t %d", dt, t);
765 program_interrupt(env, PGM_OPERAND, 6);
766 return -EINVAL;
767 }
768
769 pbdev->pba = pba;
770 pbdev->pal = pal;
771 pbdev->g_iota = g_iota;
f0a399db 772
71583888 773 s390_pci_iommu_enable(pbdev);
f0a399db 774
863f6f52
FB
775 return 0;
776}
777
e141dbad 778void pci_dereg_ioat(S390PCIBusDevice *pbdev)
863f6f52 779{
71583888 780 s390_pci_iommu_disable(pbdev);
863f6f52
FB
781 pbdev->pba = 0;
782 pbdev->pal = 0;
783 pbdev->g_iota = 0;
784}
785
6cb1e49d 786int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
863f6f52
FB
787{
788 CPUS390XState *env = &cpu->env;
a6d9d4f2 789 uint8_t oc, dmaas;
863f6f52
FB
790 uint32_t fh;
791 ZpciFib fib;
792 S390PCIBusDevice *pbdev;
793 uint64_t cc = ZPCI_PCI_LS_OK;
794
795 if (env->psw.mask & PSW_MASK_PSTATE) {
796 program_interrupt(env, PGM_PRIVILEGED, 6);
797 return 0;
798 }
799
800 oc = env->regs[r1] & 0xff;
a6d9d4f2 801 dmaas = (env->regs[r1] >> 16) & 0xff;
863f6f52
FB
802 fh = env->regs[r1] >> 32;
803
804 if (fiba & 0x7) {
805 program_interrupt(env, PGM_SPECIFICATION, 6);
806 return 0;
807 }
808
809 pbdev = s390_pci_find_dev_by_fh(fh);
5d1abf23 810 if (!pbdev) {
863f6f52
FB
811 DPRINTF("mpcifc no pci dev fh 0x%x\n", fh);
812 setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
813 return 0;
814 }
815
5d1abf23
YMZ
816 switch (pbdev->state) {
817 case ZPCI_FS_RESERVED:
818 case ZPCI_FS_STANDBY:
819 case ZPCI_FS_DISABLED:
820 case ZPCI_FS_PERMANENT_ERROR:
821 setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
822 return 0;
823 default:
824 break;
825 }
826
6cb1e49d 827 if (s390_cpu_virt_mem_read(cpu, fiba, ar, (uint8_t *)&fib, sizeof(fib))) {
63ceef61
FB
828 return 0;
829 }
863f6f52 830
a6d9d4f2
YMZ
831 if (fib.fmt != 0) {
832 program_interrupt(env, PGM_OPERAND, 6);
833 return 0;
834 }
835
863f6f52
FB
836 switch (oc) {
837 case ZPCI_MOD_FC_REG_INT:
a6d9d4f2 838 if (pbdev->summary_ind) {
863f6f52 839 cc = ZPCI_PCI_LS_ERR;
a6d9d4f2
YMZ
840 s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
841 } else if (reg_irqs(env, pbdev, fib)) {
842 cc = ZPCI_PCI_LS_ERR;
843 s390_set_status_code(env, r1, ZPCI_MOD_ST_RES_NOT_AVAIL);
863f6f52
FB
844 }
845 break;
846 case ZPCI_MOD_FC_DEREG_INT:
a6d9d4f2
YMZ
847 if (!pbdev->summary_ind) {
848 cc = ZPCI_PCI_LS_ERR;
849 s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
850 } else {
851 pci_dereg_irqs(pbdev);
852 }
863f6f52
FB
853 break;
854 case ZPCI_MOD_FC_REG_IOAT:
a6d9d4f2 855 if (dmaas != 0) {
863f6f52 856 cc = ZPCI_PCI_LS_ERR;
a6d9d4f2
YMZ
857 s390_set_status_code(env, r1, ZPCI_MOD_ST_DMAAS_INVAL);
858 } else if (pbdev->iommu_enabled) {
859 cc = ZPCI_PCI_LS_ERR;
860 s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
861 } else if (reg_ioat(env, pbdev, fib)) {
862 cc = ZPCI_PCI_LS_ERR;
863 s390_set_status_code(env, r1, ZPCI_MOD_ST_INSUF_RES);
863f6f52
FB
864 }
865 break;
866 case ZPCI_MOD_FC_DEREG_IOAT:
a6d9d4f2
YMZ
867 if (dmaas != 0) {
868 cc = ZPCI_PCI_LS_ERR;
869 s390_set_status_code(env, r1, ZPCI_MOD_ST_DMAAS_INVAL);
870 } else if (!pbdev->iommu_enabled) {
871 cc = ZPCI_PCI_LS_ERR;
872 s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
873 } else {
874 pci_dereg_ioat(pbdev);
875 }
863f6f52
FB
876 break;
877 case ZPCI_MOD_FC_REREG_IOAT:
a6d9d4f2 878 if (dmaas != 0) {
863f6f52 879 cc = ZPCI_PCI_LS_ERR;
a6d9d4f2
YMZ
880 s390_set_status_code(env, r1, ZPCI_MOD_ST_DMAAS_INVAL);
881 } else if (!pbdev->iommu_enabled) {
882 cc = ZPCI_PCI_LS_ERR;
883 s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
884 } else {
885 pci_dereg_ioat(pbdev);
886 if (reg_ioat(env, pbdev, fib)) {
887 cc = ZPCI_PCI_LS_ERR;
888 s390_set_status_code(env, r1, ZPCI_MOD_ST_INSUF_RES);
889 }
863f6f52
FB
890 }
891 break;
892 case ZPCI_MOD_FC_RESET_ERROR:
5d1abf23
YMZ
893 switch (pbdev->state) {
894 case ZPCI_FS_BLOCKED:
895 case ZPCI_FS_ERROR:
896 pbdev->state = ZPCI_FS_ENABLED;
897 break;
898 default:
899 cc = ZPCI_PCI_LS_ERR;
900 s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
901 }
863f6f52
FB
902 break;
903 case ZPCI_MOD_FC_RESET_BLOCK:
5d1abf23
YMZ
904 switch (pbdev->state) {
905 case ZPCI_FS_ERROR:
906 pbdev->state = ZPCI_FS_BLOCKED;
907 break;
908 default:
909 cc = ZPCI_PCI_LS_ERR;
910 s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
911 }
863f6f52
FB
912 break;
913 case ZPCI_MOD_FC_SET_MEASURE:
914 pbdev->fmb_addr = ldq_p(&fib.fmb_addr);
915 break;
916 default:
917 program_interrupt(&cpu->env, PGM_OPERAND, 6);
918 cc = ZPCI_PCI_LS_ERR;
919 }
920
921 setcc(cpu, cc);
922 return 0;
923}
924
6cb1e49d 925int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
863f6f52
FB
926{
927 CPUS390XState *env = &cpu->env;
928 uint32_t fh;
929 ZpciFib fib;
930 S390PCIBusDevice *pbdev;
931 uint32_t data;
932 uint64_t cc = ZPCI_PCI_LS_OK;
933
934 if (env->psw.mask & PSW_MASK_PSTATE) {
935 program_interrupt(env, PGM_PRIVILEGED, 6);
936 return 0;
937 }
938
939 fh = env->regs[r1] >> 32;
940
941 if (fiba & 0x7) {
942 program_interrupt(env, PGM_SPECIFICATION, 6);
943 return 0;
944 }
945
946 pbdev = s390_pci_find_dev_by_fh(fh);
947 if (!pbdev) {
948 setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
949 return 0;
950 }
951
952 memset(&fib, 0, sizeof(fib));
5d1abf23
YMZ
953
954 switch (pbdev->state) {
955 case ZPCI_FS_RESERVED:
956 case ZPCI_FS_STANDBY:
957 setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
958 return 0;
959 case ZPCI_FS_DISABLED:
960 if (fh & FH_MASK_ENABLE) {
961 setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
962 return 0;
963 }
964 goto out;
965 /* BLOCKED bit is set to one coincident with the setting of ERROR bit.
966 * FH Enabled bit is set to one in states of ENABLED, BLOCKED or ERROR. */
967 case ZPCI_FS_ERROR:
968 fib.fc |= 0x20;
969 case ZPCI_FS_BLOCKED:
970 fib.fc |= 0x40;
971 case ZPCI_FS_ENABLED:
972 fib.fc |= 0x80;
973 if (pbdev->iommu_enabled) {
974 fib.fc |= 0x10;
975 }
976 if (!(fh & FH_MASK_ENABLE)) {
977 env->regs[r1] |= 1ULL << 63;
978 }
979 break;
980 case ZPCI_FS_PERMANENT_ERROR:
981 setcc(cpu, ZPCI_PCI_LS_ERR);
982 s390_set_status_code(env, r1, ZPCI_STPCIFC_ST_PERM_ERROR);
983 return 0;
984 }
985
863f6f52
FB
986 stq_p(&fib.pba, pbdev->pba);
987 stq_p(&fib.pal, pbdev->pal);
988 stq_p(&fib.iota, pbdev->g_iota);
989 stq_p(&fib.aibv, pbdev->routes.adapter.ind_addr);
990 stq_p(&fib.aisb, pbdev->routes.adapter.summary_addr);
991 stq_p(&fib.fmb_addr, pbdev->fmb_addr);
992
c0eb33ab
FB
993 data = ((uint32_t)pbdev->isc << 28) | ((uint32_t)pbdev->noi << 16) |
994 ((uint32_t)pbdev->routes.adapter.ind_offset << 8) |
995 ((uint32_t)pbdev->sum << 7) | pbdev->routes.adapter.summary_offset;
996 stl_p(&fib.data, data);
863f6f52 997
5d1abf23 998out:
6cb1e49d 999 if (s390_cpu_virt_mem_write(cpu, fiba, ar, (uint8_t *)&fib, sizeof(fib))) {
63ceef61
FB
1000 return 0;
1001 }
1002
863f6f52
FB
1003 setcc(cpu, cc);
1004 return 0;
1005}
This page took 0.208134 seconds and 4 git commands to generate.