diff options
Diffstat (limited to 'hw/s390x/sclp.c')
-rw-r--r-- | hw/s390x/sclp.c | 56 |
1 files changed, 45 insertions, 11 deletions
diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index f0c35aa57a..ede056b3ef 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -33,6 +33,22 @@ static inline SCLPDevice *get_sclp_device(void) return sclp; } +static inline bool sclp_command_code_valid(uint32_t code) +{ + 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: + case SCLP_CMDW_CONFIGURE_IOA: + case SCLP_CMDW_DECONFIGURE_IOA: + case SCLP_CMD_READ_EVENT_DATA: + case SCLP_CMD_WRITE_EVENT_DATA: + case SCLP_CMD_WRITE_EVENT_MASK: + return true; + } + return false; +} + static void prepare_cpu_entries(SCLPDevice *sclp, CPUEntry *entry, int *count) { MachineState *ms = MACHINE(qdev_get_machine()); @@ -193,6 +209,34 @@ static void sclp_execute(SCLPDevice *sclp, SCCB *sccb, uint32_t code) } } +/* + * We only need the address to have something valid for the + * service_interrupt call. + */ +#define SCLP_PV_DUMMY_ADDR 0x4000 +int sclp_service_call_protected(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); + + s390_cpu_pv_mem_read(env_archcpu(env), 0, &work_sccb, sccb_len); + + if (!sclp_command_code_valid(code)) { + work_sccb.h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); + 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)); + sclp_c->service_interrupt(sclp, SCLP_PV_DUMMY_ADDR); + return 0; +} + int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code) { SCLPDevice *sclp = get_sclp_device(); @@ -225,17 +269,7 @@ int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code) return -PGM_SPECIFICATION; } - 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: - case SCLP_CMDW_CONFIGURE_IOA: - case SCLP_CMDW_DECONFIGURE_IOA: - case SCLP_CMD_READ_EVENT_DATA: - case SCLP_CMD_WRITE_EVENT_DATA: - case SCLP_CMD_WRITE_EVENT_MASK: - break; - default: + if (!sclp_command_code_valid(code)) { work_sccb.h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); goto out_write; } |