aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/s390x/s390-pci-bus.h1
-rw-r--r--hw/s390x/s390-pci-inst.c63
-rw-r--r--hw/s390x/s390-pci-inst.h2
3 files changed, 41 insertions, 25 deletions
diff --git a/hw/s390x/s390-pci-bus.h b/hw/s390x/s390-pci-bus.h
index 560bd82..2993f0d 100644
--- a/hw/s390x/s390-pci-bus.h
+++ b/hw/s390x/s390-pci-bus.h
@@ -284,6 +284,7 @@ struct S390PCIBusDevice {
uint64_t fmb_addr;
uint8_t isc;
uint16_t noi;
+ uint16_t maxstbl;
uint8_t sum;
S390MsixInfo msix;
AdapterRoutes routes;
diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c
index 48ccf22..e70cd04 100644
--- a/hw/s390x/s390-pci-inst.c
+++ b/hw/s390x/s390-pci-inst.c
@@ -297,6 +297,7 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra)
stq_p(&resgrp->msia, ZPCI_MSI_ADDR);
stw_p(&resgrp->mui, 0);
stw_p(&resgrp->i, 128);
+ stw_p(&resgrp->maxstbl, 128);
resgrp->version = 0;
stw_p(&resgrp->hdr.rsp, CLP_RC_OK);
@@ -652,6 +653,7 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr,
S390PCIBusDevice *pbdev;
MemoryRegion *mr;
MemTxResult result;
+ uint64_t offset;
int i;
uint32_t fh;
uint8_t pcias;
@@ -666,22 +668,10 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr,
fh = env->regs[r1] >> 32;
pcias = (env->regs[r1] >> 16) & 0xf;
len = env->regs[r1] & 0xff;
+ offset = env->regs[r3];
- if (pcias > 5) {
- DPRINTF("pcistb invalid space\n");
- setcc(cpu, ZPCI_PCI_LS_ERR);
- s390_set_status_code(env, r1, ZPCI_PCI_ST_INVAL_AS);
- return 0;
- }
-
- switch (len) {
- case 16:
- case 32:
- case 64:
- case 128:
- break;
- default:
- s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra);
+ if (!(fh & FH_MASK_ENABLE)) {
+ setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
return 0;
}
@@ -693,12 +683,7 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr,
}
switch (pbdev->state) {
- case ZPCI_FS_RESERVED:
- case ZPCI_FS_STANDBY:
- case ZPCI_FS_DISABLED:
case ZPCI_FS_PERMANENT_ERROR:
- setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
- return 0;
case ZPCI_FS_ERROR:
setcc(cpu, ZPCI_PCI_LS_ERR);
s390_set_status_code(env, r1, ZPCI_PCI_ST_BLOCKED);
@@ -707,8 +692,34 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr,
break;
}
+ if (pcias > ZPCI_IO_BAR_MAX) {
+ DPRINTF("pcistb invalid space\n");
+ setcc(cpu, ZPCI_PCI_LS_ERR);
+ s390_set_status_code(env, r1, ZPCI_PCI_ST_INVAL_AS);
+ return 0;
+ }
+
+ /* Verify the address, offset and length */
+ /* offset must be a multiple of 8 */
+ if (offset % 8) {
+ goto specification_error;
+ }
+ /* Length must be greater than 8, a multiple of 8 */
+ /* and not greater than maxstbl */
+ if ((len <= 8) || (len % 8) || (len > pbdev->maxstbl)) {
+ goto specification_error;
+ }
+ /* Do not cross a 4K-byte boundary */
+ if (((offset & 0xfff) + len) > 0x1000) {
+ goto specification_error;
+ }
+ /* Guest address must be double word aligned */
+ if (gaddr & 0x07UL) {
+ goto specification_error;
+ }
+
mr = pbdev->pdev->io_regions[pcias].memory;
- if (!memory_region_access_valid(mr, env->regs[r3], len, true)) {
+ if (!memory_region_access_valid(mr, offset, len, true)) {
s390_program_interrupt(env, PGM_OPERAND, 6, ra);
return 0;
}
@@ -719,9 +730,9 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr,
}
for (i = 0; i < len / 8; i++) {
- result = memory_region_dispatch_write(mr, env->regs[r3] + i * 8,
- ldq_p(buffer + i * 8), 8,
- MEMTXATTRS_UNSPECIFIED);
+ result = memory_region_dispatch_write(mr, offset + i * 8,
+ ldq_p(buffer + i * 8), 8,
+ MEMTXATTRS_UNSPECIFIED);
if (result != MEMTX_OK) {
s390_program_interrupt(env, PGM_OPERAND, 6, ra);
return 0;
@@ -730,6 +741,10 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr,
setcc(cpu, ZPCI_PCI_LS_OK);
return 0;
+
+specification_error:
+ s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra);
+ return 0;
}
static int reg_irqs(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib)
diff --git a/hw/s390x/s390-pci-inst.h b/hw/s390x/s390-pci-inst.h
index a396364..91c3d61 100644
--- a/hw/s390x/s390-pci-inst.h
+++ b/hw/s390x/s390-pci-inst.h
@@ -162,7 +162,7 @@ typedef struct ClpRspQueryPciGrp {
#define CLP_RSP_QPCIG_MASK_FRAME 0x2
#define CLP_RSP_QPCIG_MASK_REFRESH 0x1
uint8_t fr;
- uint16_t reserved2;
+ uint16_t maxstbl;
uint16_t mui;
uint64_t reserved3;
uint64_t dasm; /* dma address space mask */