int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, uint8_t ar) { CPUS390XState *env = &cpu->env; S390PCIBusDevice *pbdev; MemoryRegion *mr; int i; uint32_t fh; uint8_t pcias; uint8_t len; uint8_t buffer[128]; if (env->psw.mask & PSW_MASK_PSTATE) { program_interrupt(env, PGM_PRIVILEGED, 6); return 0; } fh = env->regs[r1] >> 32; pcias = (env->regs[r1] >> 16) & 0xf; len = env->regs[r1] & 0xff; 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: program_interrupt(env, PGM_SPECIFICATION, 6); return 0; } pbdev = s390_pci_find_dev_by_fh(fh); if (!pbdev || !(pbdev->fh & FH_MASK_ENABLE)) { DPRINTF("pcistb no pci dev fh 0x%x\n", fh); setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); return 0; } if (pbdev->lgstg_blocked) { setcc(cpu, ZPCI_PCI_LS_ERR); s390_set_status_code(env, r1, ZPCI_PCI_ST_BLOCKED); return 0; } mr = pbdev->pdev->io_regions[pcias].memory; if (!memory_region_access_valid(mr, env->regs[r3], len, true)) { program_interrupt(env, PGM_ADDRESSING, 6); return 0; } if (s390_cpu_virt_mem_read(cpu, gaddr, ar, buffer, len)) { return 0; } for (i = 0; i < len / 8; i++) { memory_region_dispatch_write(mr, env->regs[r3] + i * 8, ldq_p(buffer + i * 8), 8, MEMTXATTRS_UNSPECIFIED); } setcc(cpu, ZPCI_PCI_LS_OK); return 0; }