diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 519dc91316..9961cfe7bf 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -353,7 +353,6 @@ static ChannelSubSys channel_subsys = { .pending_crws = QTAILQ_HEAD_INITIALIZER(channel_subsys.pending_crws), .do_crw_mchk = true, .sei_pending = false, - .do_crw_mchk = true, .crws_lost = false, .chnmon_active = false, .indicator_addresses = diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c index 645b4080c5..ed92ce510d 100644 --- a/hw/s390x/event-facility.c +++ b/hw/s390x/event-facility.c @@ -213,7 +213,7 @@ static uint16_t handle_sccb_read_events(SCLPEventFacility *ef, SCCB *sccb, event_buf = &red->ebh; event_buf->length = 0; - slen = sizeof(sccb->data); + slen = sccb_data_len(sccb); rc = SCLP_RC_NO_EVENT_BUFFERS_STORED; diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index a0ce444b4b..00f1e4648d 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -49,9 +49,37 @@ static inline bool sclp_command_code_valid(uint32_t code) return false; } -static void prepare_cpu_entries(SCLPDevice *sclp, CPUEntry *entry, int *count) +static bool sccb_verify_boundary(uint64_t sccb_addr, uint16_t sccb_len, + uint32_t code) +{ + uint64_t sccb_max_addr = sccb_addr + sccb_len - 1; + uint64_t sccb_boundary = (sccb_addr & PAGE_MASK) + PAGE_SIZE; + + switch (code & SCLP_CMD_CODE_MASK) { + case SCLP_CMDW_READ_SCP_INFO: + case SCLP_CMDW_READ_SCP_INFO_FORCED: + case SCLP_CMDW_READ_CPU_INFO: + /* + * An extended-length SCCB is only allowed for Read SCP/CPU Info and + * is allowed to exceed the 4k boundary. The respective commands will + * set the length field to the required length if an insufficient + * SCCB length is provided. + */ + if (s390_has_feat(S390_FEAT_EXTENDED_LENGTH_SCCB)) { + return true; + } + /* fallthrough */ + default: + if (sccb_max_addr < sccb_boundary) { + return true; + } + } + + return false; +} + +static void prepare_cpu_entries(MachineState *ms, CPUEntry *entry, int *count) { - MachineState *ms = MACHINE(qdev_get_machine()); uint8_t features[SCCB_CPU_FEATURE_LEN] = { 0 }; int i; @@ -67,6 +95,14 @@ static void prepare_cpu_entries(SCLPDevice *sclp, CPUEntry *entry, int *count) } } +#define SCCB_REQ_LEN(s, max_cpus) (sizeof(s) + max_cpus * sizeof(CPUEntry)) + +static inline bool ext_len_sccb_supported(SCCBHeader header) +{ + return s390_has_feat(S390_FEAT_EXTENDED_LENGTH_SCCB) && + header.control_mask[2] & SCLP_VARIABLE_LENGTH_RESPONSE; +} + /* Provide information about the configuration, CPUs and storage */ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb) { @@ -75,27 +111,39 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb) int cpu_count; int rnsize, rnmax; IplParameterBlock *ipib = s390_ipl_get_iplb(); + int required_len = SCCB_REQ_LEN(ReadInfo, machine->possible_cpus->len); + int offset_cpu = s390_has_feat(S390_FEAT_EXTENDED_LENGTH_SCCB) ? + offsetof(ReadInfo, entries) : + SCLP_READ_SCP_INFO_FIXED_CPU_OFFSET; + CPUEntry *entries_start = (void *)sccb + offset_cpu; - /* CPU information */ - prepare_cpu_entries(sclp, read_info->entries, &cpu_count); - read_info->entries_cpu = cpu_to_be16(cpu_count); - read_info->offset_cpu = cpu_to_be16(offsetof(ReadInfo, entries)); - read_info->highest_cpu = cpu_to_be16(machine->smp.max_cpus - 1); - - read_info->ibc_val = cpu_to_be32(s390_get_ibc_val()); - - if (be16_to_cpu(sccb->h.length) < - (sizeof(ReadInfo) + cpu_count * sizeof(CPUEntry))) { + if (be16_to_cpu(sccb->h.length) < required_len) { + if (ext_len_sccb_supported(sccb->h)) { + sccb->h.length = cpu_to_be16(required_len); + } sccb->h.response_code = cpu_to_be16(SCLP_RC_INSUFFICIENT_SCCB_LENGTH); return; } + /* CPU information */ + prepare_cpu_entries(machine, entries_start, &cpu_count); + read_info->entries_cpu = cpu_to_be16(cpu_count); + read_info->offset_cpu = cpu_to_be16(offset_cpu); + read_info->highest_cpu = cpu_to_be16(machine->smp.max_cpus - 1); + + read_info->ibc_val = cpu_to_be32(s390_get_ibc_val()); + /* Configuration Characteristic (Extension) */ s390_get_feat_block(S390_FEAT_TYPE_SCLP_CONF_CHAR, read_info->conf_char); s390_get_feat_block(S390_FEAT_TYPE_SCLP_CONF_CHAR_EXT, read_info->conf_char_ext); + if (s390_has_feat(S390_FEAT_EXTENDED_LENGTH_SCCB)) { + s390_get_feat_block(S390_FEAT_TYPE_SCLP_FAC134, + &read_info->fac134); + } + read_info->facilities = cpu_to_be64(SCLP_HAS_CPU_INFO | SCLP_HAS_IOA_RECONFIG); @@ -132,20 +180,24 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb) /* Provide information about the CPU */ static void sclp_read_cpu_info(SCLPDevice *sclp, SCCB *sccb) { + MachineState *machine = MACHINE(qdev_get_machine()); ReadCpuInfo *cpu_info = (ReadCpuInfo *) sccb; int cpu_count; + int required_len = SCCB_REQ_LEN(ReadCpuInfo, machine->possible_cpus->len); - prepare_cpu_entries(sclp, cpu_info->entries, &cpu_count); - cpu_info->nr_configured = cpu_to_be16(cpu_count); - cpu_info->offset_configured = cpu_to_be16(offsetof(ReadCpuInfo, entries)); - cpu_info->nr_standby = cpu_to_be16(0); - - if (be16_to_cpu(sccb->h.length) < - (sizeof(ReadCpuInfo) + cpu_count * sizeof(CPUEntry))) { + if (be16_to_cpu(sccb->h.length) < required_len) { + if (ext_len_sccb_supported(sccb->h)) { + sccb->h.length = cpu_to_be16(required_len); + } sccb->h.response_code = cpu_to_be16(SCLP_RC_INSUFFICIENT_SCCB_LENGTH); return; } + prepare_cpu_entries(machine, cpu_info->entries, &cpu_count); + cpu_info->nr_configured = cpu_to_be16(cpu_count); + cpu_info->offset_configured = cpu_to_be16(offsetof(ReadCpuInfo, entries)); + cpu_info->nr_standby = cpu_to_be16(0); + /* The standby offset is 16-byte for each CPU */ cpu_info->offset_standby = cpu_to_be16(cpu_info->offset_configured + cpu_info->nr_configured*sizeof(CPUEntry)); @@ -219,20 +271,29 @@ int sclp_service_call_protected(CPUS390XState *env, uint64_t sccb, { SCLPDevice *sclp = get_sclp_device(); SCLPDeviceClass *sclp_c = SCLP_GET_CLASS(sclp); - SCCB work_sccb; - hwaddr sccb_len = sizeof(SCCB); + SCCBHeader header; + g_autofree SCCB *work_sccb = NULL; - s390_cpu_pv_mem_read(env_archcpu(env), 0, &work_sccb, sccb_len); + s390_cpu_pv_mem_read(env_archcpu(env), 0, &header, sizeof(SCCBHeader)); + + work_sccb = g_malloc0(be16_to_cpu(header.length)); + s390_cpu_pv_mem_read(env_archcpu(env), 0, work_sccb, + be16_to_cpu(header.length)); if (!sclp_command_code_valid(code)) { - work_sccb.h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); + work_sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); goto out_write; } - sclp_c->execute(sclp, &work_sccb, code); + if (!sccb_verify_boundary(sccb, be16_to_cpu(work_sccb->h.length), code)) { + work_sccb->h.response_code = cpu_to_be16(SCLP_RC_SCCB_BOUNDARY_VIOLATION); + goto out_write; + } + + sclp_c->execute(sclp, work_sccb, code); out_write: - s390_cpu_pv_mem_write(env_archcpu(env), 0, &work_sccb, - be16_to_cpu(work_sccb.h.length)); + s390_cpu_pv_mem_write(env_archcpu(env), 0, work_sccb, + be16_to_cpu(work_sccb->h.length)); sclp_c->service_interrupt(sclp, SCLP_PV_DUMMY_ADDR); return 0; } @@ -241,9 +302,8 @@ int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code) { SCLPDevice *sclp = get_sclp_device(); SCLPDeviceClass *sclp_c = SCLP_GET_CLASS(sclp); - SCCB work_sccb; - - hwaddr sccb_len = sizeof(SCCB); + SCCBHeader header; + g_autofree SCCB *work_sccb = NULL; /* first some basic checks on program checks */ if (env->psw.mask & PSW_MASK_PSTATE) { @@ -257,32 +317,36 @@ int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code) return -PGM_SPECIFICATION; } + /* the header contains the actual length of the sccb */ + cpu_physical_memory_read(sccb, &header, sizeof(SCCBHeader)); + + /* Valid sccb sizes */ + if (be16_to_cpu(header.length) < sizeof(SCCBHeader)) { + return -PGM_SPECIFICATION; + } + /* * we want to work on a private copy of the sccb, to prevent guests * from playing dirty tricks by modifying the memory content after * the host has checked the values */ - cpu_physical_memory_read(sccb, &work_sccb, sccb_len); - - /* Valid sccb sizes */ - if (be16_to_cpu(work_sccb.h.length) < sizeof(SCCBHeader)) { - return -PGM_SPECIFICATION; - } + work_sccb = g_malloc0(be16_to_cpu(header.length)); + cpu_physical_memory_read(sccb, work_sccb, be16_to_cpu(header.length)); if (!sclp_command_code_valid(code)) { - work_sccb.h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); + work_sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); goto out_write; } - if ((sccb + be16_to_cpu(work_sccb.h.length)) > ((sccb & PAGE_MASK) + PAGE_SIZE)) { - work_sccb.h.response_code = cpu_to_be16(SCLP_RC_SCCB_BOUNDARY_VIOLATION); + if (!sccb_verify_boundary(sccb, be16_to_cpu(work_sccb->h.length), code)) { + work_sccb->h.response_code = cpu_to_be16(SCLP_RC_SCCB_BOUNDARY_VIOLATION); goto out_write; } - sclp_c->execute(sclp, &work_sccb, code); + sclp_c->execute(sclp, work_sccb, code); out_write: - cpu_physical_memory_write(sccb, &work_sccb, - be16_to_cpu(work_sccb.h.length)); + cpu_physical_memory_write(sccb, work_sccb, + be16_to_cpu(work_sccb->h.length)); sclp_c->service_interrupt(sclp, sccb); diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c index ff7f369779..d2755d7fc5 100644 --- a/hw/vfio/ccw.c +++ b/hw/vfio/ccw.c @@ -491,6 +491,7 @@ static void vfio_ccw_get_region(VFIOCCWDevice *vcdev, Error **errp) vcdev->io_region_offset = info->offset; vcdev->io_region = g_malloc0(info->size); + g_free(info); /* check for the optional async command region */ ret = vfio_get_dev_region_info(vdev, VFIO_REGION_TYPE_CCW, @@ -503,6 +504,7 @@ static void vfio_ccw_get_region(VFIOCCWDevice *vcdev, Error **errp) } vcdev->async_cmd_region_offset = info->offset; vcdev->async_cmd_region = g_malloc0(info->size); + g_free(info); } ret = vfio_get_dev_region_info(vdev, VFIO_REGION_TYPE_CCW, @@ -515,6 +517,7 @@ static void vfio_ccw_get_region(VFIOCCWDevice *vcdev, Error **errp) } vcdev->schib_region_offset = info->offset; vcdev->schib_region = g_malloc(info->size); + g_free(info); } ret = vfio_get_dev_region_info(vdev, VFIO_REGION_TYPE_CCW, @@ -528,9 +531,9 @@ static void vfio_ccw_get_region(VFIOCCWDevice *vcdev, Error **errp) } vcdev->crw_region_offset = info->offset; vcdev->crw_region = g_malloc(info->size); + g_free(info); } - g_free(info); return; out_err: diff --git a/include/hw/s390x/sclp.h b/include/hw/s390x/sclp.h index cd730772f9..d3ade40a5a 100644 --- a/include/hw/s390x/sclp.h +++ b/include/hw/s390x/sclp.h @@ -111,6 +111,7 @@ typedef struct CPUEntry { uint8_t reserved1; } QEMU_PACKED CPUEntry; +#define SCLP_READ_SCP_INFO_FIXED_CPU_OFFSET 128 typedef struct ReadInfo { SCCBHeader h; uint16_t rnmax; @@ -133,7 +134,15 @@ typedef struct ReadInfo { uint16_t highest_cpu; uint8_t _reserved5[124 - 122]; /* 122-123 */ uint32_t hmfai; + uint8_t _reserved7[134 - 128]; /* 128-133 */ + uint8_t fac134; + uint8_t _reserved8[144 - 135]; /* 135-143 */ struct CPUEntry entries[]; + /* + * When the Extended-Length SCCB (ELS) feature is enabled the + * start of the entries field begins at an offset denoted by the + * offset_cpu field, otherwise it's at an offset of 128. + */ } QEMU_PACKED ReadInfo; typedef struct ReadCpuInfo { @@ -178,7 +187,7 @@ typedef struct IoaCfgSccb { typedef struct SCCB { SCCBHeader h; - char data[SCCB_DATA_LEN]; + char data[]; } QEMU_PACKED SCCB; #define TYPE_SCLP "sclp" diff --git a/target/s390x/cc_helper.c b/target/s390x/cc_helper.c index 44731e4a85..5432aeeed4 100644 --- a/target/s390x/cc_helper.c +++ b/target/s390x/cc_helper.c @@ -417,6 +417,32 @@ static uint32_t cc_calc_vc(uint64_t low, uint64_t high) } } +static uint32_t cc_calc_muls_32(int64_t res) +{ + const int64_t tmp = res >> 31; + + if (!res) { + return 0; + } else if (tmp && tmp != -1) { + return 3; + } else if (res < 0) { + return 1; + } + return 2; +} + +static uint64_t cc_calc_muls_64(int64_t res_high, uint64_t res_low) +{ + if (!res_high && !res_low) { + return 0; + } else if (res_high + (res_low >> 63) != 0) { + return 3; + } else if (res_high < 0) { + return 1; + } + return 2; +} + static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst, uint64_t vr) { @@ -484,6 +510,9 @@ static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, case CC_OP_COMP_64: r = cc_calc_comp_64(dst); break; + case CC_OP_MULS_64: + r = cc_calc_muls_64(src, dst); + break; case CC_OP_ADD_32: r = cc_calc_add_32(src, dst, vr); @@ -512,6 +541,9 @@ static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, case CC_OP_COMP_32: r = cc_calc_comp_32(dst); break; + case CC_OP_MULS_32: + r = cc_calc_muls_32(dst); + break; case CC_OP_ICM: r = cc_calc_icm(src, dst); diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index 035427521c..f875ebf0f4 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -112,6 +112,8 @@ struct CPUS390XState { uint16_t external_call_addr; DECLARE_BITMAP(emergency_signals, S390_MAX_CPUS); + uint64_t diag318_info; + /* Fields up to this point are cleared by a CPU reset */ struct {} end_reset_fields; diff --git a/target/s390x/cpu_features.h b/target/s390x/cpu_features.h index 2a29475493..ef52ffce83 100644 --- a/target/s390x/cpu_features.h +++ b/target/s390x/cpu_features.h @@ -23,6 +23,7 @@ typedef enum { S390_FEAT_TYPE_STFL, S390_FEAT_TYPE_SCLP_CONF_CHAR, S390_FEAT_TYPE_SCLP_CONF_CHAR_EXT, + S390_FEAT_TYPE_SCLP_FAC134, S390_FEAT_TYPE_SCLP_CPU, S390_FEAT_TYPE_MISC, S390_FEAT_TYPE_PLO, diff --git a/target/s390x/cpu_features_def.h.inc b/target/s390x/cpu_features_def.h.inc index 5942f81f16..7db3449e04 100644 --- a/target/s390x/cpu_features_def.h.inc +++ b/target/s390x/cpu_features_def.h.inc @@ -72,7 +72,7 @@ DEF_FEAT(INTERLOCKED_ACCESS_2, "iacc2", STFL, 52, "Interlocked-access facility 2 DEF_FEAT(STFLE_53, "stfle53", STFL, 53, "Various facilities introduced with z13") DEF_FEAT(ENTROPY_ENC_COMP, "eec", STFL, 54, "Entropy encoding compression facility") DEF_FEAT(MSA_EXT_5, "msa5-base", STFL, 57, "Message-security-assist-extension-5 facility (excluding subfunctions)") -DEF_FEAT(MISC_INSTRUCTION_EXT, "minste2", STFL, 58, "Miscellaneous-instruction-extensions facility 2") +DEF_FEAT(MISC_INSTRUCTION_EXT2, "minste2", STFL, 58, "Miscellaneous-instruction-extensions facility 2") DEF_FEAT(SEMAPHORE_ASSIST, "sema", STFL, 59, "Semaphore-assist facility") DEF_FEAT(TIME_SLICE_INSTRUMENTATION, "tsi", STFL, 60, "Time-slice Instrumentation facility") DEF_FEAT(MISC_INSTRUCTION_EXT3, "minste3", STFL, 61, "Miscellaneous-Instruction-Extensions Facility 3") @@ -97,6 +97,7 @@ DEF_FEAT(GUARDED_STORAGE, "gs", STFL, 133, "Guarded-storage facility") DEF_FEAT(VECTOR_PACKED_DECIMAL, "vxpd", STFL, 134, "Vector packed decimal facility") DEF_FEAT(VECTOR_ENH, "vxeh", STFL, 135, "Vector enhancements facility") DEF_FEAT(MULTIPLE_EPOCH, "mepoch", STFL, 139, "Multiple-epoch facility") +DEF_FEAT(EXTENDED_LENGTH_SCCB, "els", STFL, 140, "Extended-length SCCB facility") DEF_FEAT(TEST_PENDING_EXT_INTERRUPTION, "tpei", STFL, 144, "Test-pending-external-interruption facility") DEF_FEAT(INSERT_REFERENCE_BITS_MULT, "irbm", STFL, 145, "Insert-reference-bits-multiple facility") DEF_FEAT(MSA_EXT_8, "msa8-base", STFL, 146, "Message-security-assist-extension-8 facility (excluding subfunctions)") @@ -121,6 +122,9 @@ DEF_FEAT(SIE_CMMA, "cmma", SCLP_CONF_CHAR_EXT, 1, "SIE: Collaborative-memory-man DEF_FEAT(SIE_PFMFI, "pfmfi", SCLP_CONF_CHAR_EXT, 9, "SIE: PFMF interpretation facility") DEF_FEAT(SIE_IBS, "ibs", SCLP_CONF_CHAR_EXT, 10, "SIE: Interlock-and-broadcast-suppression facility") +/* Features exposed via SCLP SCCB Facilities byte 134 (bit numbers relative to byte-134) */ +DEF_FEAT(DIAG_318, "diag318", SCLP_FAC134, 0, "Control program name and version codes") + /* Features exposed via SCLP CPU info. */ DEF_FEAT(SIE_F2, "sief2", SCLP_CPU, 4, "SIE: interception format 2 (Virtual SIE)") DEF_FEAT(SIE_SKEY, "skey", SCLP_CPU, 5, "SIE: Storage-key facility") diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c index b97e9596ab..ca484bfda7 100644 --- a/target/s390x/cpu_models.c +++ b/target/s390x/cpu_models.c @@ -824,6 +824,7 @@ static void check_consistency(const S390CPUModel *model) { S390_FEAT_PTFF_STOE, S390_FEAT_MULTIPLE_EPOCH }, { S390_FEAT_PTFF_STOUE, S390_FEAT_MULTIPLE_EPOCH }, { S390_FEAT_AP_QUEUE_INTERRUPT_CONTROL, S390_FEAT_AP }, + { S390_FEAT_DIAG_318, S390_FEAT_EXTENDED_LENGTH_SCCB }, }; int i; diff --git a/target/s390x/excp_helper.c b/target/s390x/excp_helper.c index 3b58d10df3..0adfbbda27 100644 --- a/target/s390x/excp_helper.c +++ b/target/s390x/excp_helper.c @@ -610,4 +610,27 @@ void s390x_cpu_do_unaligned_access(CPUState *cs, vaddr addr, tcg_s390_program_interrupt(env, PGM_SPECIFICATION, retaddr); } +static void QEMU_NORETURN monitor_event(CPUS390XState *env, + uint64_t monitor_code, + uint8_t monitor_class, uintptr_t ra) +{ + /* Store the Monitor Code and the Monitor Class Number into the lowcore */ + stq_phys(env_cpu(env)->as, + env->psa + offsetof(LowCore, monitor_code), monitor_code); + stw_phys(env_cpu(env)->as, + env->psa + offsetof(LowCore, mon_class_num), monitor_class); + + tcg_s390_program_interrupt(env, PGM_MONITOR, ra); +} + +void HELPER(monitor_call)(CPUS390XState *env, uint64_t monitor_code, + uint32_t monitor_class) +{ + g_assert(monitor_class <= 0xff); + + if (env->cregs[8] & (0x8000 >> monitor_class)) { + monitor_event(env, monitor_code, monitor_class, GETPC()); + } +} + #endif /* CONFIG_USER_ONLY */ diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c index 8ddeebc544..a6ec918e90 100644 --- a/target/s390x/gen-features.c +++ b/target/s390x/gen-features.c @@ -412,7 +412,7 @@ static uint16_t base_GEN13_GA1[] = { static uint16_t base_GEN14_GA1[] = { S390_FEAT_ENTROPY_ENC_COMP, - S390_FEAT_MISC_INSTRUCTION_EXT, + S390_FEAT_MISC_INSTRUCTION_EXT2, S390_FEAT_SEMAPHORE_ASSIST, S390_FEAT_TIME_SLICE_INSTRUMENTATION, S390_FEAT_ORDER_PRESERVING_COMPRESSION, @@ -522,6 +522,8 @@ static uint16_t full_GEN12_GA1[] = { S390_FEAT_AP_QUEUE_INTERRUPT_CONTROL, S390_FEAT_AP_FACILITIES_TEST, S390_FEAT_AP, + S390_FEAT_EXTENDED_LENGTH_SCCB, + S390_FEAT_DIAG_318, }; static uint16_t full_GEN12_GA2[] = { @@ -716,6 +718,8 @@ static uint16_t qemu_MAX[] = { S390_FEAT_MSA_EXT_5, /* features introduced after the z13 */ S390_FEAT_INSTRUCTION_EXEC_PROT, + S390_FEAT_MISC_INSTRUCTION_EXT2, + S390_FEAT_MSA_EXT_8, }; /****** END FEATURE DEFS ******/ diff --git a/target/s390x/helper.c b/target/s390x/helper.c index 9257d388ba..b877690845 100644 --- a/target/s390x/helper.c +++ b/target/s390x/helper.c @@ -430,6 +430,8 @@ const char *cc_name(enum cc_op cc_op) [CC_OP_FLOGR] = "CC_OP_FLOGR", [CC_OP_LCBB] = "CC_OP_LCBB", [CC_OP_VC] = "CC_OP_VC", + [CC_OP_MULS_32] = "CC_OP_MULS_32", + [CC_OP_MULS_64] = "CC_OP_MULS_64", }; return cc_names[cc_op]; diff --git a/target/s390x/helper.h b/target/s390x/helper.h index b7887b552b..55bd1551e6 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -349,4 +349,5 @@ DEF_HELPER_3(sic, void, env, i64, i64) DEF_HELPER_3(rpcit, void, env, i32, i32) DEF_HELPER_5(pcistb, void, env, i32, i32, i64, i32) DEF_HELPER_4(mpcifc, void, env, i32, i64, i32) +DEF_HELPER_3(monitor_call, void, env, i64, i32) #endif diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index d79ae9e3f1..d3bcdfd67b 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -52,6 +52,7 @@ /* ADD HALFWORD */ C(0x4a00, AH, RX_a, Z, r1, m2_16s, new, r1_32, add, adds32) C(0xe37a, AHY, RXY_a, LD, r1, m2_16s, new, r1_32, add, adds32) + C(0xe338, AGH, RXY_a, MIE2,r1, m2_16s, r1, 0, add, adds64) /* ADD HALFWORD IMMEDIATE */ C(0xa70a, AHI, RI_a, Z, r1, i2, new, r1_32, add, adds32) C(0xa70b, AGHI, RI_a, Z, r1, i2, r1, 0, add, adds64) @@ -114,6 +115,8 @@ /* BRANCH RELATIVE AND SAVE */ C(0xa705, BRAS, RI_b, Z, 0, 0, r1, 0, basi, 0) C(0xc005, BRASL, RIL_b, Z, 0, 0, r1, 0, basi, 0) +/* BRANCH INDIRECT ON CONDITION */ + C(0xe347, BIC, RXY_b, MIE2,0, m2_64w, 0, 0, bc, 0) /* BRANCH ON CONDITION */ C(0x0700, BCR, RR_b, Z, 0, r2_nz, 0, 0, bc, 0) C(0x4700, BC, RX_b, Z, 0, a2, 0, 0, bc, 0) @@ -617,6 +620,9 @@ C(0x9a00, LAM, RS_a, Z, 0, a2, 0, 0, lam, 0) C(0xeb9a, LAMY, RSY_a, LD, 0, a2, 0, 0, lam, 0) +/* MONITOR CALL */ + C(0xaf00, MC, SI, Z, la1, 0, 0, 0, mc, 0) + /* MOVE */ C(0xd200, MVC, SS_a, Z, la1, a2, 0, 0, mvc, 0) C(0xe544, MVHHI, SIL, GIE, la1, i2, 0, m1_16, mov2, 0) @@ -649,8 +655,10 @@ /* MULTIPLY */ C(0x1c00, MR, RR_a, Z, r1p1_32s, r2_32s, new, r1_D32, mul, 0) + C(0xb9ec, MGRK, RRF_a, MIE2,r3_o, r2_o, r1_P, 0, muls128, 0) C(0x5c00, M, RX_a, Z, r1p1_32s, m2_32s, new, r1_D32, mul, 0) C(0xe35c, MFY, RXY_a, GIE, r1p1_32s, m2_32s, new, r1_D32, mul, 0) + C(0xe384, MG, RXY_a, MIE2,r1p1_o, m2_64, r1_P, 0, muls128, 0) F(0xb317, MEEBR, RRE, Z, e1, e2, new, e1, meeb, 0, IF_BFP) F(0xb31c, MDBR, RRE, Z, f1, f2, new, f1, mdb, 0, IF_BFP) F(0xb34c, MXBR, RRE, Z, x2h, x2l, x1, x1, mxb, 0, IF_BFP) @@ -663,6 +671,7 @@ /* MULTIPLY HALFWORD */ C(0x4c00, MH, RX_a, Z, r1_o, m2_16s, new, r1_32, mul, 0) C(0xe37c, MHY, RXY_a, GIE, r1_o, m2_16s, new, r1_32, mul, 0) + C(0xe33c, MGH, RXY_a, MIE2,r1_o, m2_16s, r1, 0, mul, 0) /* MULTIPLY HALFWORD IMMEDIATE */ C(0xa70c, MHI, RI_a, Z, r1_o, i2, new, r1_32, mul, 0) C(0xa70d, MGHI, RI_a, Z, r1_o, i2, r1, 0, mul, 0) @@ -673,11 +682,15 @@ C(0xe386, MLG, RXY_a, Z, r1p1, m2_64, r1_P, 0, mul128, 0) /* MULTIPLY SINGLE */ C(0xb252, MSR, RRE, Z, r1_o, r2_o, new, r1_32, mul, 0) + C(0xb9fd, MSRKC, RRF_a, MIE2,r3_32s, r2_32s, new, r1_32, mul, muls32) C(0x7100, MS, RX_a, Z, r1_o, m2_32s, new, r1_32, mul, 0) C(0xe351, MSY, RXY_a, LD, r1_o, m2_32s, new, r1_32, mul, 0) + C(0xe353, MSC, RXY_a, MIE2,r1_32s, m2_32s, new, r1_32, mul, muls32) C(0xb90c, MSGR, RRE, Z, r1_o, r2_o, r1, 0, mul, 0) + C(0xb9ed, MSGRKC, RRF_a, MIE2,r3_o, r2_o, new_P, out2_r1, muls128, muls64) C(0xb91c, MSGFR, RRE, Z, r1_o, r2_32s, r1, 0, mul, 0) C(0xe30c, MSG, RXY_a, Z, r1_o, m2_64, r1, 0, mul, 0) + C(0xe383, MSGC, RXY_a, MIE2,r1_o, m2_64, new_P, out2_r1, muls128, muls64) C(0xe31c, MSGF, RXY_a, Z, r1_o, m2_32s, r1, 0, mul, 0) /* MULTIPLY SINGLE IMMEDIATE */ C(0xc201, MSFI, RIL_a, GIE, r1_o, i2, new, r1_32, mul, 0) @@ -882,6 +895,7 @@ /* SUBTRACT HALFWORD */ C(0x4b00, SH, RX_a, Z, r1, m2_16s, new, r1_32, sub, subs32) C(0xe37b, SHY, RXY_a, LD, r1, m2_16s, new, r1_32, sub, subs32) + C(0xe339, SGH, RXY_a, MIE2,r1, m2_16s, r1, 0, sub, subs64) /* SUBTRACT HIGH */ C(0xb9c9, SHHHR, RRF_a, HW, r2_sr32, r3_sr32, new, r1_32h, sub, subs32) C(0xb9d9, SHHLR, RRF_a, HW, r2_sr32, r3, new, r1_32h, sub, subs32) @@ -968,6 +982,7 @@ D(0xb92d, KMCTR, RRF_b, MSA4, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KMCTR) D(0xb92e, KM, RRE, MSA, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KM) D(0xb92f, KMC, RRE, MSA, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KMC) + D(0xb929, KMA, RRF_b, MSA8, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KMA) D(0xb93c, PPNO, RRE, MSA5, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_PPNO) D(0xb93e, KIMD, RRE, MSA, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KIMD) D(0xb93f, KLMD, RRE, MSA, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KLMD) diff --git a/target/s390x/internal.h b/target/s390x/internal.h index bac0d3c67b..64602660ae 100644 --- a/target/s390x/internal.h +++ b/target/s390x/internal.h @@ -175,6 +175,7 @@ enum cc_op { CC_OP_SUBB_64, /* overflow on unsigned sub-borrow (64bit) */ CC_OP_ABS_64, /* sign eval on abs (64bit) */ CC_OP_NABS_64, /* sign eval on nabs (64bit) */ + CC_OP_MULS_64, /* overflow on signed multiply (64bit) */ CC_OP_ADD_32, /* overflow on add (32bit) */ CC_OP_ADDU_32, /* overflow on unsigned add (32bit) */ @@ -184,6 +185,7 @@ enum cc_op { CC_OP_SUBB_32, /* overflow on unsigned sub-borrow (32bit) */ CC_OP_ABS_32, /* sign eval on abs (64bit) */ CC_OP_NABS_32, /* sign eval on nabs (64bit) */ + CC_OP_MULS_32, /* overflow on signed multiply (32bit) */ CC_OP_COMP_32, /* complement */ CC_OP_COMP_64, /* complement */ diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c index f2f75d2a57..f13eff688c 100644 --- a/target/s390x/kvm.c +++ b/target/s390x/kvm.c @@ -105,6 +105,7 @@ #define DIAG_TIMEREVENT 0x288 #define DIAG_IPL 0x308 +#define DIAG_SET_CONTROL_PROGRAM_CODES 0x318 #define DIAG_KVM_HYPERCALL 0x500 #define DIAG_KVM_BREAKPOINT 0x501 @@ -602,6 +603,11 @@ int kvm_arch_put_registers(CPUState *cs, int level) cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_ETOKEN; } + if (can_sync_regs(cs, KVM_SYNC_DIAG318)) { + cs->kvm_run->s.regs.diag318 = env->diag318_info; + cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_DIAG318; + } + /* Finally the prefix */ if (can_sync_regs(cs, KVM_SYNC_PREFIX)) { cs->kvm_run->s.regs.prefix = env->psa; @@ -741,6 +747,10 @@ int kvm_arch_get_registers(CPUState *cs) } } + if (can_sync_regs(cs, KVM_SYNC_DIAG318)) { + env->diag318_info = cs->kvm_run->s.regs.diag318; + } + return 0; } @@ -1601,6 +1611,27 @@ static int handle_sw_breakpoint(S390CPU *cpu, struct kvm_run *run) return -ENOENT; } +static void handle_diag_318(S390CPU *cpu, struct kvm_run *run) +{ + uint64_t reg = (run->s390_sieic.ipa & 0x00f0) >> 4; + uint64_t diag318_info = run->s.regs.gprs[reg]; + + /* + * DIAG 318 can only be enabled with KVM support. As such, let's + * ensure a guest cannot execute this instruction erroneously. + */ + if (!s390_has_feat(S390_FEAT_DIAG_318)) { + kvm_s390_program_interrupt(cpu, PGM_SPECIFICATION); + } + + cpu->env.diag318_info = diag318_info; + + if (can_sync_regs(CPU(cpu), KVM_SYNC_DIAG318)) { + run->s.regs.diag318 = diag318_info; + run->kvm_dirty_regs |= KVM_SYNC_DIAG318; + } +} + #define DIAG_KVM_CODE_MASK 0x000000000000ffff static int handle_diag(S390CPU *cpu, struct kvm_run *run, uint32_t ipb) @@ -1620,6 +1651,9 @@ static int handle_diag(S390CPU *cpu, struct kvm_run *run, uint32_t ipb) case DIAG_IPL: kvm_handle_diag_308(cpu, run); break; + case DIAG_SET_CONTROL_PROGRAM_CODES: + handle_diag_318(cpu, run); + break; case DIAG_KVM_HYPERCALL: r = handle_hypercall(cpu, run); break; @@ -2456,6 +2490,19 @@ void kvm_s390_get_host_cpu_model(S390CPUModel *model, Error **errp) KVM_S390_VM_CRYPTO_ENABLE_APIE)) { set_bit(S390_FEAT_AP, model->features); } + + /* + * Extended-Length SCCB is handled entirely within QEMU. + * For PV guests this is completely fenced by the Ultravisor, as Service + * Call error checking and STFLE interpretation are handled via SIE. + */ + set_bit(S390_FEAT_EXTENDED_LENGTH_SCCB, model->features); + + /* DIAGNOSE 0x318 is not supported under protected virtualization */ + if (!s390_is_pv() && kvm_check_extension(kvm_state, KVM_CAP_S390_DIAG318)) { + set_bit(S390_FEAT_DIAG_318, model->features); + } + /* strip of features that are not part of the maximum model */ bitmap_and(model->features, model->features, model->def->full_feat, S390_FEAT_MAX); diff --git a/target/s390x/machine.c b/target/s390x/machine.c index 549bb6c280..5b4e82f1ab 100644 --- a/target/s390x/machine.c +++ b/target/s390x/machine.c @@ -234,6 +234,22 @@ const VMStateDescription vmstate_etoken = { } }; +static bool diag318_needed(void *opaque) +{ + return s390_has_feat(S390_FEAT_DIAG_318); +} + +const VMStateDescription vmstate_diag318 = { + .name = "cpu/diag318", + .version_id = 1, + .minimum_version_id = 1, + .needed = diag318_needed, + .fields = (VMStateField[]) { + VMSTATE_UINT64(env.diag318_info, S390CPU), + VMSTATE_END_OF_LIST() + } +}; + const VMStateDescription vmstate_s390_cpu = { .name = "cpu", .post_load = cpu_post_load, @@ -270,6 +286,7 @@ const VMStateDescription vmstate_s390_cpu = { &vmstate_gscb, &vmstate_bpbc, &vmstate_etoken, + &vmstate_diag318, NULL }, }; diff --git a/target/s390x/translate.c b/target/s390x/translate.c index a777343821..ac10f42f10 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -646,6 +646,7 @@ static void gen_op_calc_cc(DisasContext *s) case CC_OP_NZ_F64: case CC_OP_FLOGR: case CC_OP_LCBB: + case CC_OP_MULS_32: /* 1 argument */ gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, dummy, cc_dst, dummy); break; @@ -660,6 +661,7 @@ static void gen_op_calc_cc(DisasContext *s) case CC_OP_SLA_64: case CC_OP_NZ_F128: case CC_OP_VC: + case CC_OP_MULS_64: /* 2 arguments */ gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, cc_src, cc_dst, dummy); break; @@ -2708,6 +2710,12 @@ static DisasJumpType op_msa(DisasContext *s, DisasOps *o) TCGv_i32 t_r1, t_r2, t_r3, type; switch (s->insn->data) { + case S390_FEAT_TYPE_KMA: + if (r3 == r1 || r3 == r2) { + gen_program_exception(s, PGM_SPECIFICATION); + return DISAS_NORETURN; + } + /* FALL THROUGH */ case S390_FEAT_TYPE_KMCTR: if (r3 & 1 || !r3) { gen_program_exception(s, PGM_SPECIFICATION); @@ -3302,6 +3310,27 @@ static DisasJumpType op_lcbb(DisasContext *s, DisasOps *o) return DISAS_NEXT; } +static DisasJumpType op_mc(DisasContext *s, DisasOps *o) +{ +#if !defined(CONFIG_USER_ONLY) + TCGv_i32 i2; +#endif + const uint16_t monitor_class = get_field(s, i2); + + if (monitor_class & 0xff00) { + gen_program_exception(s, PGM_SPECIFICATION); + return DISAS_NORETURN; + } + +#if !defined(CONFIG_USER_ONLY) + i2 = tcg_const_i32(monitor_class); + gen_helper_monitor_call(cpu_env, o->addr1, i2); + tcg_temp_free_i32(i2); +#endif + /* Defaults to a NOP. */ + return DISAS_NEXT; +} + static DisasJumpType op_mov2(DisasContext *s, DisasOps *o) { o->out = o->in2; @@ -3518,6 +3547,12 @@ static DisasJumpType op_mul128(DisasContext *s, DisasOps *o) return DISAS_NEXT; } +static DisasJumpType op_muls128(DisasContext *s, DisasOps *o) +{ + tcg_gen_muls2_i64(o->out2, o->out, o->in1, o->in2); + return DISAS_NEXT; +} + static DisasJumpType op_meeb(DisasContext *s, DisasOps *o) { gen_helper_meeb(o->out, cpu_env, o->in1, o->in2); @@ -5283,6 +5318,17 @@ static void cout_tm64(DisasContext *s, DisasOps *o) gen_op_update2_cc_i64(s, CC_OP_TM_64, o->in1, o->in2); } +static void cout_muls32(DisasContext *s, DisasOps *o) +{ + gen_op_update1_cc_i64(s, CC_OP_MULS_32, o->out); +} + +static void cout_muls64(DisasContext *s, DisasOps *o) +{ + /* out contains "high" part, out2 contains "low" part of 128 bit result */ + gen_op_update2_cc_i64(s, CC_OP_MULS_64, o->out, o->out2); +} + /* ====================================================================== */ /* The "PREParation" generators. These initialize the DisasOps.OUT fields with the TCG register to which we will write. Used in combination with @@ -5338,6 +5384,12 @@ static void wout_r1(DisasContext *s, DisasOps *o) } #define SPEC_wout_r1 0 +static void wout_out2_r1(DisasContext *s, DisasOps *o) +{ + store_reg(get_field(s, r1), o->out2); +} +#define SPEC_wout_out2_r1 0 + static void wout_r1_8(DisasContext *s, DisasOps *o) { int r1 = get_field(s, r1); @@ -5542,6 +5594,13 @@ static void in1_r1p1(DisasContext *s, DisasOps *o) } #define SPEC_in1_r1p1 SPEC_r1_even +static void in1_r1p1_o(DisasContext *s, DisasOps *o) +{ + o->in1 = regs[get_field(s, r1) + 1]; + o->g_in1 = true; +} +#define SPEC_in1_r1p1_o SPEC_r1_even + static void in1_r1p1_32s(DisasContext *s, DisasOps *o) { o->in1 = tcg_temp_new_i64(); @@ -5922,6 +5981,14 @@ static void in2_m2_64(DisasContext *s, DisasOps *o) } #define SPEC_in2_m2_64 0 +static void in2_m2_64w(DisasContext *s, DisasOps *o) +{ + in2_a2(s, o); + tcg_gen_qemu_ld64(o->in2, o->in2, get_mem_index(s)); + gen_addi_and_wrap_i64(s, o->in2, o->in2, 0); +} +#define SPEC_in2_m2_64w 0 + #ifndef CONFIG_USER_ONLY static void in2_m2_64a(DisasContext *s, DisasOps *o) { @@ -6093,11 +6160,13 @@ enum DisasInsnEnum { #define FAC_MSA3 S390_FEAT_MSA_EXT_3 /* msa-extension-3 facility */ #define FAC_MSA4 S390_FEAT_MSA_EXT_4 /* msa-extension-4 facility */ #define FAC_MSA5 S390_FEAT_MSA_EXT_5 /* msa-extension-5 facility */ +#define FAC_MSA8 S390_FEAT_MSA_EXT_8 /* msa-extension-8 facility */ #define FAC_ECT S390_FEAT_EXTRACT_CPU_TIME #define FAC_PCI S390_FEAT_ZPCI /* z/PCI facility */ #define FAC_AIS S390_FEAT_ADAPTER_INT_SUPPRESSION #define FAC_V S390_FEAT_VECTOR /* vector facility */ #define FAC_VE S390_FEAT_VECTOR_ENH /* vector enhancements facility 1 */ +#define FAC_MIE2 S390_FEAT_MISC_INSTRUCTION_EXT2 /* miscellaneous-instruction-extensions facility 2 */ static const DisasInsn insn_info[] = { #include "insn-data.def"