Heinz Graalfs | f6c98f92 | 2012-10-29 02:13:22 +0000 | [diff] [blame] | 1 | /* |
| 2 | * SCLP Support |
| 3 | * |
| 4 | * Copyright IBM, Corp. 2012 |
| 5 | * |
| 6 | * Authors: |
| 7 | * Christian Borntraeger <borntraeger@de.ibm.com> |
| 8 | * Heinz Graalfs <graalfs@linux.vnet.ibm.com> |
| 9 | * |
| 10 | * This work is licensed under the terms of the GNU GPL, version 2 or (at your |
| 11 | * option) any later version. See the COPYING file in the top-level directory. |
| 12 | * |
| 13 | */ |
| 14 | |
Peter Maydell | 9615495 | 2016-01-26 18:17:00 +0000 | [diff] [blame] | 15 | #include "qemu/osdep.h" |
Philippe Mathieu-Daudé | 393fc4c | 2018-06-25 09:42:11 -0300 | [diff] [blame] | 16 | #include "qemu/units.h" |
Markus Armbruster | da34e65 | 2016-03-14 09:01:28 +0100 | [diff] [blame] | 17 | #include "qapi/error.h" |
Heinz Graalfs | f6c98f92 | 2012-10-29 02:13:22 +0000 | [diff] [blame] | 18 | #include "cpu.h" |
Jason J. Herne | 8cc3aec | 2014-01-20 14:51:49 -0500 | [diff] [blame] | 19 | #include "sysemu/sysemu.h" |
David Hildenbrand | 311467f | 2015-05-29 13:14:50 +0200 | [diff] [blame] | 20 | #include "hw/boards.h" |
Paolo Bonzini | 83c9f4c | 2013-02-04 15:40:22 +0100 | [diff] [blame] | 21 | #include "hw/s390x/sclp.h" |
Heinz Graalfs | 477a72a | 2013-12-18 10:10:49 +0100 | [diff] [blame] | 22 | #include "hw/s390x/event-facility.h" |
Frank Blaschka | 8cba80c | 2015-01-09 09:04:38 +0100 | [diff] [blame] | 23 | #include "hw/s390x/s390-pci-bus.h" |
Farhan Ali | b038411 | 2016-03-29 16:34:37 +0200 | [diff] [blame] | 24 | #include "hw/s390x/ipl.h" |
Heinz Graalfs | f6c98f92 | 2012-10-29 02:13:22 +0000 | [diff] [blame] | 25 | |
David Hildenbrand | 25a3c5a | 2015-05-27 10:04:56 +0200 | [diff] [blame] | 26 | static inline SCLPDevice *get_sclp_device(void) |
| 27 | { |
Christian Borntraeger | 989fd86 | 2016-08-10 12:14:19 +0200 | [diff] [blame] | 28 | static SCLPDevice *sclp; |
| 29 | |
| 30 | if (!sclp) { |
| 31 | sclp = SCLP(object_resolve_path_type("", TYPE_SCLP, NULL)); |
| 32 | } |
| 33 | return sclp; |
David Hildenbrand | 25a3c5a | 2015-05-27 10:04:56 +0200 | [diff] [blame] | 34 | } |
| 35 | |
David Hildenbrand | bb535bb | 2017-09-13 15:24:16 +0200 | [diff] [blame] | 36 | static void prepare_cpu_entries(SCLPDevice *sclp, CPUEntry *entry, int *count) |
David Hildenbrand | 026546e | 2016-09-05 10:52:27 +0200 | [diff] [blame] | 37 | { |
David Hildenbrand | bb535bb | 2017-09-13 15:24:16 +0200 | [diff] [blame] | 38 | MachineState *ms = MACHINE(qdev_get_machine()); |
David Hildenbrand | 4dd4200 | 2016-09-05 10:52:29 +0200 | [diff] [blame] | 39 | uint8_t features[SCCB_CPU_FEATURE_LEN] = { 0 }; |
David Hildenbrand | 026546e | 2016-09-05 10:52:27 +0200 | [diff] [blame] | 40 | int i; |
| 41 | |
David Hildenbrand | 4dd4200 | 2016-09-05 10:52:29 +0200 | [diff] [blame] | 42 | s390_get_feat_block(S390_FEAT_TYPE_SCLP_CPU, features); |
David Hildenbrand | bb535bb | 2017-09-13 15:24:16 +0200 | [diff] [blame] | 43 | for (i = 0, *count = 0; i < ms->possible_cpus->len; i++) { |
| 44 | if (!ms->possible_cpus->cpus[i].cpu) { |
| 45 | continue; |
| 46 | } |
| 47 | entry[*count].address = ms->possible_cpus->cpus[i].arch_id; |
| 48 | entry[*count].type = 0; |
| 49 | memcpy(entry[*count].features, features, sizeof(features)); |
| 50 | (*count)++; |
David Hildenbrand | 026546e | 2016-09-05 10:52:27 +0200 | [diff] [blame] | 51 | } |
| 52 | } |
| 53 | |
Heinz Graalfs | f6c98f92 | 2012-10-29 02:13:22 +0000 | [diff] [blame] | 54 | /* Provide information about the configuration, CPUs and storage */ |
David Hildenbrand | 25a3c5a | 2015-05-27 10:04:56 +0200 | [diff] [blame] | 55 | static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb) |
Heinz Graalfs | f6c98f92 | 2012-10-29 02:13:22 +0000 | [diff] [blame] | 56 | { |
| 57 | ReadInfo *read_info = (ReadInfo *) sccb; |
David Hildenbrand | 311467f | 2015-05-29 13:14:50 +0200 | [diff] [blame] | 58 | MachineState *machine = MACHINE(qdev_get_machine()); |
David Hildenbrand | bb535bb | 2017-09-13 15:24:16 +0200 | [diff] [blame] | 59 | int cpu_count; |
Matthew Rosato | 1def665 | 2014-08-28 11:25:35 -0400 | [diff] [blame] | 60 | int rnsize, rnmax; |
Farhan Ali | b038411 | 2016-03-29 16:34:37 +0200 | [diff] [blame] | 61 | IplParameterBlock *ipib = s390_ipl_get_iplb(); |
Jason J. Herne | 8cc3aec | 2014-01-20 14:51:49 -0500 | [diff] [blame] | 62 | |
Jason J. Herne | 8cc3aec | 2014-01-20 14:51:49 -0500 | [diff] [blame] | 63 | /* CPU information */ |
David Hildenbrand | bb535bb | 2017-09-13 15:24:16 +0200 | [diff] [blame] | 64 | prepare_cpu_entries(sclp, read_info->entries, &cpu_count); |
Jason J. Herne | 8cc3aec | 2014-01-20 14:51:49 -0500 | [diff] [blame] | 65 | read_info->entries_cpu = cpu_to_be16(cpu_count); |
| 66 | read_info->offset_cpu = cpu_to_be16(offsetof(ReadInfo, entries)); |
Like Xu | ae71ed8 | 2019-05-19 04:54:24 +0800 | [diff] [blame] | 67 | read_info->highest_cpu = cpu_to_be16(machine->smp.max_cpus - 1); |
Jason J. Herne | 8cc3aec | 2014-01-20 14:51:49 -0500 | [diff] [blame] | 68 | |
David Hildenbrand | 059be52 | 2016-09-05 10:52:30 +0200 | [diff] [blame] | 69 | read_info->ibc_val = cpu_to_be32(s390_get_ibc_val()); |
| 70 | |
Claudio Imbrenda | 832be0d | 2019-09-27 15:33:23 +0200 | [diff] [blame] | 71 | if (be16_to_cpu(sccb->h.length) < |
| 72 | (sizeof(ReadInfo) + cpu_count * sizeof(CPUEntry))) { |
| 73 | sccb->h.response_code = cpu_to_be16(SCLP_RC_INSUFFICIENT_SCCB_LENGTH); |
| 74 | return; |
| 75 | } |
| 76 | |
David Hildenbrand | 4dd4200 | 2016-09-05 10:52:29 +0200 | [diff] [blame] | 77 | /* Configuration Characteristic (Extension) */ |
| 78 | s390_get_feat_block(S390_FEAT_TYPE_SCLP_CONF_CHAR, |
| 79 | read_info->conf_char); |
| 80 | s390_get_feat_block(S390_FEAT_TYPE_SCLP_CONF_CHAR_EXT, |
| 81 | read_info->conf_char_ext); |
| 82 | |
Frank Blaschka | 8cba80c | 2015-01-09 09:04:38 +0100 | [diff] [blame] | 83 | read_info->facilities = cpu_to_be64(SCLP_HAS_CPU_INFO | |
Cornelia Huck | 80b7a26 | 2017-07-06 17:13:14 +0200 | [diff] [blame] | 84 | SCLP_HAS_IOA_RECONFIG); |
Heinz Graalfs | f6c98f92 | 2012-10-29 02:13:22 +0000 | [diff] [blame] | 85 | |
David Hildenbrand | 3fad325 | 2016-09-05 10:52:31 +0200 | [diff] [blame] | 86 | read_info->mha_pow = s390_get_mha_pow(); |
David Hildenbrand | a366930 | 2016-09-05 10:52:32 +0200 | [diff] [blame] | 87 | read_info->hmfai = cpu_to_be32(s390_get_hmfai()); |
Matthew Rosato | 1def665 | 2014-08-28 11:25:35 -0400 | [diff] [blame] | 88 | |
David Hildenbrand | 71a2fd3 | 2015-06-01 13:03:23 +0200 | [diff] [blame] | 89 | rnsize = 1 << (sclp->increment_size - 20); |
Matthew Rosato | 1def665 | 2014-08-28 11:25:35 -0400 | [diff] [blame] | 90 | if (rnsize <= 128) { |
| 91 | read_info->rnsize = rnsize; |
| 92 | } else { |
| 93 | read_info->rnsize = 0; |
| 94 | read_info->rnsize2 = cpu_to_be32(rnsize); |
| 95 | } |
| 96 | |
David Hildenbrand | 82fab5c | 2018-02-19 18:42:31 +0100 | [diff] [blame] | 97 | /* we don't support standby memory, maxram_size is never exposed */ |
| 98 | rnmax = machine->ram_size >> sclp->increment_size; |
Matthew Rosato | 1def665 | 2014-08-28 11:25:35 -0400 | [diff] [blame] | 99 | if (rnmax < 0x10000) { |
| 100 | read_info->rnmax = cpu_to_be16(rnmax); |
| 101 | } else { |
| 102 | read_info->rnmax = cpu_to_be16(0); |
| 103 | read_info->rnmax2 = cpu_to_be64(rnmax); |
| 104 | } |
| 105 | |
Farhan Ali | b038411 | 2016-03-29 16:34:37 +0200 | [diff] [blame] | 106 | if (ipib && ipib->flags & DIAG308_FLAGS_LP_VALID) { |
| 107 | memcpy(&read_info->loadparm, &ipib->loadparm, |
| 108 | sizeof(read_info->loadparm)); |
| 109 | } else { |
| 110 | s390_ipl_set_loadparm(read_info->loadparm); |
| 111 | } |
| 112 | |
Heinz Graalfs | f6c98f92 | 2012-10-29 02:13:22 +0000 | [diff] [blame] | 113 | sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION); |
| 114 | } |
| 115 | |
Jason J. Herne | 8cc3aec | 2014-01-20 14:51:49 -0500 | [diff] [blame] | 116 | /* Provide information about the CPU */ |
David Hildenbrand | 25a3c5a | 2015-05-27 10:04:56 +0200 | [diff] [blame] | 117 | static void sclp_read_cpu_info(SCLPDevice *sclp, SCCB *sccb) |
Jason J. Herne | 8cc3aec | 2014-01-20 14:51:49 -0500 | [diff] [blame] | 118 | { |
| 119 | ReadCpuInfo *cpu_info = (ReadCpuInfo *) sccb; |
David Hildenbrand | bb535bb | 2017-09-13 15:24:16 +0200 | [diff] [blame] | 120 | int cpu_count; |
Jason J. Herne | 8cc3aec | 2014-01-20 14:51:49 -0500 | [diff] [blame] | 121 | |
David Hildenbrand | bb535bb | 2017-09-13 15:24:16 +0200 | [diff] [blame] | 122 | prepare_cpu_entries(sclp, cpu_info->entries, &cpu_count); |
Jason J. Herne | 8cc3aec | 2014-01-20 14:51:49 -0500 | [diff] [blame] | 123 | cpu_info->nr_configured = cpu_to_be16(cpu_count); |
| 124 | cpu_info->offset_configured = cpu_to_be16(offsetof(ReadCpuInfo, entries)); |
| 125 | cpu_info->nr_standby = cpu_to_be16(0); |
| 126 | |
Claudio Imbrenda | 832be0d | 2019-09-27 15:33:23 +0200 | [diff] [blame] | 127 | if (be16_to_cpu(sccb->h.length) < |
| 128 | (sizeof(ReadCpuInfo) + cpu_count * sizeof(CPUEntry))) { |
| 129 | sccb->h.response_code = cpu_to_be16(SCLP_RC_INSUFFICIENT_SCCB_LENGTH); |
| 130 | return; |
| 131 | } |
| 132 | |
Jason J. Herne | 8cc3aec | 2014-01-20 14:51:49 -0500 | [diff] [blame] | 133 | /* The standby offset is 16-byte for each CPU */ |
| 134 | cpu_info->offset_standby = cpu_to_be16(cpu_info->offset_configured |
| 135 | + cpu_info->nr_configured*sizeof(CPUEntry)); |
| 136 | |
Jason J. Herne | 8cc3aec | 2014-01-20 14:51:49 -0500 | [diff] [blame] | 137 | |
| 138 | sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION); |
| 139 | } |
| 140 | |
Cornelia Huck | 80b7a26 | 2017-07-06 17:13:14 +0200 | [diff] [blame] | 141 | static void sclp_configure_io_adapter(SCLPDevice *sclp, SCCB *sccb, |
| 142 | bool configure) |
| 143 | { |
| 144 | int rc; |
| 145 | |
| 146 | if (be16_to_cpu(sccb->h.length) < 16) { |
| 147 | rc = SCLP_RC_INSUFFICIENT_SCCB_LENGTH; |
| 148 | goto out_err; |
| 149 | } |
| 150 | |
| 151 | switch (((IoaCfgSccb *)sccb)->atype) { |
| 152 | case SCLP_RECONFIG_PCI_ATYPE: |
| 153 | if (s390_has_feat(S390_FEAT_ZPCI)) { |
| 154 | if (configure) { |
| 155 | s390_pci_sclp_configure(sccb); |
| 156 | } else { |
| 157 | s390_pci_sclp_deconfigure(sccb); |
| 158 | } |
| 159 | return; |
| 160 | } |
| 161 | /* fallthrough */ |
| 162 | default: |
| 163 | rc = SCLP_RC_ADAPTER_TYPE_NOT_RECOGNIZED; |
| 164 | } |
| 165 | |
| 166 | out_err: |
| 167 | sccb->h.response_code = cpu_to_be16(rc); |
| 168 | } |
| 169 | |
David Hildenbrand | 25a3c5a | 2015-05-27 10:04:56 +0200 | [diff] [blame] | 170 | static void sclp_execute(SCLPDevice *sclp, SCCB *sccb, uint32_t code) |
Heinz Graalfs | f6c98f92 | 2012-10-29 02:13:22 +0000 | [diff] [blame] | 171 | { |
David Hildenbrand | 25a3c5a | 2015-05-27 10:04:56 +0200 | [diff] [blame] | 172 | SCLPDeviceClass *sclp_c = SCLP_GET_CLASS(sclp); |
| 173 | SCLPEventFacility *ef = sclp->event_facility; |
Heinz Graalfs | 477a72a | 2013-12-18 10:10:49 +0100 | [diff] [blame] | 174 | SCLPEventFacilityClass *efc = EVENT_FACILITY_GET_CLASS(ef); |
Heinz Graalfs | 559a17a | 2012-10-29 02:13:23 +0000 | [diff] [blame] | 175 | |
Jason J. Herne | 5f04c14 | 2014-01-20 14:51:48 -0500 | [diff] [blame] | 176 | switch (code & SCLP_CMD_CODE_MASK) { |
Heinz Graalfs | f6c98f92 | 2012-10-29 02:13:22 +0000 | [diff] [blame] | 177 | case SCLP_CMDW_READ_SCP_INFO: |
| 178 | case SCLP_CMDW_READ_SCP_INFO_FORCED: |
David Hildenbrand | 25a3c5a | 2015-05-27 10:04:56 +0200 | [diff] [blame] | 179 | sclp_c->read_SCP_info(sclp, sccb); |
Heinz Graalfs | f6c98f92 | 2012-10-29 02:13:22 +0000 | [diff] [blame] | 180 | break; |
Jason J. Herne | 8cc3aec | 2014-01-20 14:51:49 -0500 | [diff] [blame] | 181 | case SCLP_CMDW_READ_CPU_INFO: |
David Hildenbrand | 25a3c5a | 2015-05-27 10:04:56 +0200 | [diff] [blame] | 182 | sclp_c->read_cpu_info(sclp, sccb); |
Jason J. Herne | 8cc3aec | 2014-01-20 14:51:49 -0500 | [diff] [blame] | 183 | break; |
Cornelia Huck | 80b7a26 | 2017-07-06 17:13:14 +0200 | [diff] [blame] | 184 | case SCLP_CMDW_CONFIGURE_IOA: |
| 185 | sclp_configure_io_adapter(sclp, sccb, true); |
Frank Blaschka | 8cba80c | 2015-01-09 09:04:38 +0100 | [diff] [blame] | 186 | break; |
Cornelia Huck | 80b7a26 | 2017-07-06 17:13:14 +0200 | [diff] [blame] | 187 | case SCLP_CMDW_DECONFIGURE_IOA: |
| 188 | sclp_configure_io_adapter(sclp, sccb, false); |
Frank Blaschka | 8cba80c | 2015-01-09 09:04:38 +0100 | [diff] [blame] | 189 | break; |
Heinz Graalfs | f6c98f92 | 2012-10-29 02:13:22 +0000 | [diff] [blame] | 190 | default: |
Heinz Graalfs | 477a72a | 2013-12-18 10:10:49 +0100 | [diff] [blame] | 191 | efc->command_handler(ef, sccb, code); |
Heinz Graalfs | f6c98f92 | 2012-10-29 02:13:22 +0000 | [diff] [blame] | 192 | break; |
| 193 | } |
| 194 | } |
| 195 | |
Thomas Huth | 6e25280 | 2014-01-13 12:55:55 +0100 | [diff] [blame] | 196 | int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code) |
Heinz Graalfs | f6c98f92 | 2012-10-29 02:13:22 +0000 | [diff] [blame] | 197 | { |
David Hildenbrand | 25a3c5a | 2015-05-27 10:04:56 +0200 | [diff] [blame] | 198 | SCLPDevice *sclp = get_sclp_device(); |
| 199 | SCLPDeviceClass *sclp_c = SCLP_GET_CLASS(sclp); |
Heinz Graalfs | f6c98f92 | 2012-10-29 02:13:22 +0000 | [diff] [blame] | 200 | int r = 0; |
| 201 | SCCB work_sccb; |
| 202 | |
| 203 | hwaddr sccb_len = sizeof(SCCB); |
| 204 | |
| 205 | /* first some basic checks on program checks */ |
Thomas Huth | 6e25280 | 2014-01-13 12:55:55 +0100 | [diff] [blame] | 206 | if (env->psw.mask & PSW_MASK_PSTATE) { |
| 207 | r = -PGM_PRIVILEGED; |
| 208 | goto out; |
| 209 | } |
Heinz Graalfs | f6c98f92 | 2012-10-29 02:13:22 +0000 | [diff] [blame] | 210 | if (cpu_physical_memory_is_io(sccb)) { |
| 211 | r = -PGM_ADDRESSING; |
| 212 | goto out; |
| 213 | } |
Thomas Huth | 6e25280 | 2014-01-13 12:55:55 +0100 | [diff] [blame] | 214 | if ((sccb & ~0x1fffUL) == 0 || (sccb & ~0x1fffUL) == env->psa |
| 215 | || (sccb & ~0x7ffffff8UL) != 0) { |
Heinz Graalfs | f6c98f92 | 2012-10-29 02:13:22 +0000 | [diff] [blame] | 216 | r = -PGM_SPECIFICATION; |
| 217 | goto out; |
| 218 | } |
| 219 | |
| 220 | /* |
| 221 | * we want to work on a private copy of the sccb, to prevent guests |
| 222 | * from playing dirty tricks by modifying the memory content after |
| 223 | * the host has checked the values |
| 224 | */ |
| 225 | cpu_physical_memory_read(sccb, &work_sccb, sccb_len); |
| 226 | |
| 227 | /* Valid sccb sizes */ |
Janosch Frank | d959f6c | 2019-09-27 15:33:22 +0200 | [diff] [blame] | 228 | if (be16_to_cpu(work_sccb.h.length) < sizeof(SCCBHeader)) { |
Heinz Graalfs | f6c98f92 | 2012-10-29 02:13:22 +0000 | [diff] [blame] | 229 | r = -PGM_SPECIFICATION; |
| 230 | goto out; |
| 231 | } |
| 232 | |
Janosch Frank | 679b844 | 2019-09-27 15:33:20 +0200 | [diff] [blame] | 233 | switch (code & SCLP_CMD_CODE_MASK) { |
| 234 | case SCLP_CMDW_READ_SCP_INFO: |
| 235 | case SCLP_CMDW_READ_SCP_INFO_FORCED: |
| 236 | case SCLP_CMDW_READ_CPU_INFO: |
| 237 | case SCLP_CMDW_CONFIGURE_IOA: |
| 238 | case SCLP_CMDW_DECONFIGURE_IOA: |
| 239 | case SCLP_CMD_READ_EVENT_DATA: |
| 240 | case SCLP_CMD_WRITE_EVENT_DATA: |
| 241 | case SCLP_CMD_WRITE_EVENT_MASK: |
| 242 | break; |
| 243 | default: |
| 244 | work_sccb.h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); |
| 245 | goto out_write; |
| 246 | } |
Heinz Graalfs | f6c98f92 | 2012-10-29 02:13:22 +0000 | [diff] [blame] | 247 | |
Janosch Frank | 6f6c933 | 2019-09-27 15:33:21 +0200 | [diff] [blame] | 248 | if ((sccb + be16_to_cpu(work_sccb.h.length)) > ((sccb & PAGE_MASK) + PAGE_SIZE)) { |
| 249 | work_sccb.h.response_code = cpu_to_be16(SCLP_RC_SCCB_BOUNDARY_VIOLATION); |
| 250 | goto out_write; |
| 251 | } |
| 252 | |
Janosch Frank | 679b844 | 2019-09-27 15:33:20 +0200 | [diff] [blame] | 253 | sclp_c->execute(sclp, &work_sccb, code); |
| 254 | out_write: |
Heinz Graalfs | f6c98f92 | 2012-10-29 02:13:22 +0000 | [diff] [blame] | 255 | cpu_physical_memory_write(sccb, &work_sccb, |
| 256 | be16_to_cpu(work_sccb.h.length)); |
| 257 | |
David Hildenbrand | 1723a1b | 2015-05-13 15:06:44 +0200 | [diff] [blame] | 258 | sclp_c->service_interrupt(sclp, sccb); |
Heinz Graalfs | f6c98f92 | 2012-10-29 02:13:22 +0000 | [diff] [blame] | 259 | |
| 260 | out: |
| 261 | return r; |
| 262 | } |
| 263 | |
David Hildenbrand | 1723a1b | 2015-05-13 15:06:44 +0200 | [diff] [blame] | 264 | static void service_interrupt(SCLPDevice *sclp, uint32_t sccb) |
Heinz Graalfs | f6c98f92 | 2012-10-29 02:13:22 +0000 | [diff] [blame] | 265 | { |
David Hildenbrand | 1723a1b | 2015-05-13 15:06:44 +0200 | [diff] [blame] | 266 | SCLPEventFacility *ef = sclp->event_facility; |
Heinz Graalfs | 477a72a | 2013-12-18 10:10:49 +0100 | [diff] [blame] | 267 | SCLPEventFacilityClass *efc = EVENT_FACILITY_GET_CLASS(ef); |
| 268 | |
Heinz Graalfs | 559a17a | 2012-10-29 02:13:23 +0000 | [diff] [blame] | 269 | uint32_t param = sccb & ~3; |
| 270 | |
| 271 | /* Indicate whether an event is still pending */ |
Heinz Graalfs | 477a72a | 2013-12-18 10:10:49 +0100 | [diff] [blame] | 272 | param |= efc->event_pending(ef) ? 1 : 0; |
Heinz Graalfs | 559a17a | 2012-10-29 02:13:23 +0000 | [diff] [blame] | 273 | |
| 274 | if (!param) { |
| 275 | /* No need to send an interrupt, there's nothing to be notified about */ |
| 276 | return; |
| 277 | } |
| 278 | s390_sclp_extint(param); |
Heinz Graalfs | f6c98f92 | 2012-10-29 02:13:22 +0000 | [diff] [blame] | 279 | } |
| 280 | |
David Hildenbrand | 1723a1b | 2015-05-13 15:06:44 +0200 | [diff] [blame] | 281 | void sclp_service_interrupt(uint32_t sccb) |
| 282 | { |
| 283 | SCLPDevice *sclp = get_sclp_device(); |
| 284 | SCLPDeviceClass *sclp_c = SCLP_GET_CLASS(sclp); |
| 285 | |
| 286 | sclp_c->service_interrupt(sclp, sccb); |
| 287 | } |
| 288 | |
Heinz Graalfs | f6c98f92 | 2012-10-29 02:13:22 +0000 | [diff] [blame] | 289 | /* qemu object creation and initialization functions */ |
| 290 | |
Heinz Graalfs | 559a17a | 2012-10-29 02:13:23 +0000 | [diff] [blame] | 291 | void s390_sclp_init(void) |
| 292 | { |
David Hildenbrand | 515190d | 2015-05-27 09:49:43 +0200 | [diff] [blame] | 293 | Object *new = object_new(TYPE_SCLP); |
Heinz Graalfs | 559a17a | 2012-10-29 02:13:23 +0000 | [diff] [blame] | 294 | |
David Hildenbrand | 515190d | 2015-05-27 09:49:43 +0200 | [diff] [blame] | 295 | object_property_add_child(qdev_get_machine(), TYPE_SCLP, new, |
| 296 | NULL); |
| 297 | object_unref(OBJECT(new)); |
| 298 | qdev_init_nofail(DEVICE(new)); |
Heinz Graalfs | 559a17a | 2012-10-29 02:13:23 +0000 | [diff] [blame] | 299 | } |
Matthew Rosato | 0844df7 | 2014-08-28 11:25:32 -0400 | [diff] [blame] | 300 | |
David Hildenbrand | 515190d | 2015-05-27 09:49:43 +0200 | [diff] [blame] | 301 | static void sclp_realize(DeviceState *dev, Error **errp) |
| 302 | { |
David Hildenbrand | 1cf065f | 2015-05-29 13:53:08 +0200 | [diff] [blame] | 303 | MachineState *machine = MACHINE(qdev_get_machine()); |
David Hildenbrand | 515190d | 2015-05-27 09:49:43 +0200 | [diff] [blame] | 304 | SCLPDevice *sclp = SCLP(dev); |
Markus Armbruster | e6da780 | 2015-12-18 16:35:25 +0100 | [diff] [blame] | 305 | Error *err = NULL; |
David Hildenbrand | 1cf065f | 2015-05-29 13:53:08 +0200 | [diff] [blame] | 306 | uint64_t hw_limit; |
| 307 | int ret; |
David Hildenbrand | 515190d | 2015-05-27 09:49:43 +0200 | [diff] [blame] | 308 | |
| 309 | object_property_set_bool(OBJECT(sclp->event_facility), true, "realized", |
Markus Armbruster | e6da780 | 2015-12-18 16:35:25 +0100 | [diff] [blame] | 310 | &err); |
| 311 | if (err) { |
Markus Armbruster | 24da21f | 2015-12-18 16:35:26 +0100 | [diff] [blame] | 312 | goto out; |
David Hildenbrand | 515190d | 2015-05-27 09:49:43 +0200 | [diff] [blame] | 313 | } |
David Hildenbrand | 8b638c4 | 2015-11-23 13:03:08 +0100 | [diff] [blame] | 314 | /* |
| 315 | * qdev_device_add searches the sysbus for TYPE_SCLP_EVENTS_BUS. As long |
| 316 | * as we can't find a fitting bus via the qom tree, we have to add the |
| 317 | * event facility to the sysbus, so e.g. a sclp console can be created. |
| 318 | */ |
| 319 | qdev_set_parent_bus(DEVICE(sclp->event_facility), sysbus_get_default()); |
David Hildenbrand | 1cf065f | 2015-05-29 13:53:08 +0200 | [diff] [blame] | 320 | |
| 321 | ret = s390_set_memory_limit(machine->maxram_size, &hw_limit); |
| 322 | if (ret == -E2BIG) { |
Ishani Chugh | d0e31a1 | 2017-04-13 21:44:39 +0530 | [diff] [blame] | 323 | error_setg(&err, "host supports a maximum of %" PRIu64 " GB", |
Philippe Mathieu-Daudé | 393fc4c | 2018-06-25 09:42:11 -0300 | [diff] [blame] | 324 | hw_limit / GiB); |
David Hildenbrand | 1cf065f | 2015-05-29 13:53:08 +0200 | [diff] [blame] | 325 | } else if (ret) { |
Ishani Chugh | d0e31a1 | 2017-04-13 21:44:39 +0530 | [diff] [blame] | 326 | error_setg(&err, "setting the guest size failed"); |
David Hildenbrand | 1cf065f | 2015-05-29 13:53:08 +0200 | [diff] [blame] | 327 | } |
Markus Armbruster | 24da21f | 2015-12-18 16:35:26 +0100 | [diff] [blame] | 328 | |
| 329 | out: |
Markus Armbruster | e6da780 | 2015-12-18 16:35:25 +0100 | [diff] [blame] | 330 | error_propagate(errp, err); |
David Hildenbrand | 515190d | 2015-05-27 09:49:43 +0200 | [diff] [blame] | 331 | } |
| 332 | |
David Hildenbrand | 1cf065f | 2015-05-29 13:53:08 +0200 | [diff] [blame] | 333 | static void sclp_memory_init(SCLPDevice *sclp) |
| 334 | { |
| 335 | MachineState *machine = MACHINE(qdev_get_machine()); |
| 336 | ram_addr_t initial_mem = machine->ram_size; |
David Hildenbrand | 1cf065f | 2015-05-29 13:53:08 +0200 | [diff] [blame] | 337 | int increment_size = 20; |
| 338 | |
| 339 | /* The storage increment size is a multiple of 1M and is a power of 2. |
| 340 | * The number of storage increments must be MAX_STORAGE_INCREMENTS or fewer. |
| 341 | * The variable 'increment_size' is an exponent of 2 that can be |
| 342 | * used to calculate the size (in bytes) of an increment. */ |
| 343 | while ((initial_mem >> increment_size) > MAX_STORAGE_INCREMENTS) { |
| 344 | increment_size++; |
| 345 | } |
David Hildenbrand | 71a2fd3 | 2015-06-01 13:03:23 +0200 | [diff] [blame] | 346 | sclp->increment_size = increment_size; |
David Hildenbrand | 1cf065f | 2015-05-29 13:53:08 +0200 | [diff] [blame] | 347 | |
David Hildenbrand | 82fab5c | 2018-02-19 18:42:31 +0100 | [diff] [blame] | 348 | /* The core memory area needs to be aligned with the increment size. |
| 349 | * In effect, this can cause the user-specified memory size to be rounded |
| 350 | * down to align with the nearest increment boundary. */ |
David Hildenbrand | 1cf065f | 2015-05-29 13:53:08 +0200 | [diff] [blame] | 351 | initial_mem = initial_mem >> increment_size << increment_size; |
David Hildenbrand | 1cf065f | 2015-05-29 13:53:08 +0200 | [diff] [blame] | 352 | |
David Hildenbrand | 1cf065f | 2015-05-29 13:53:08 +0200 | [diff] [blame] | 353 | machine->ram_size = initial_mem; |
Christian Borntraeger | 408e5ac | 2018-07-30 16:09:26 +0200 | [diff] [blame] | 354 | machine->maxram_size = initial_mem; |
David Hildenbrand | 1cf065f | 2015-05-29 13:53:08 +0200 | [diff] [blame] | 355 | /* let's propagate the changed ram size into the global variable. */ |
| 356 | ram_size = initial_mem; |
| 357 | } |
| 358 | |
David Hildenbrand | 515190d | 2015-05-27 09:49:43 +0200 | [diff] [blame] | 359 | static void sclp_init(Object *obj) |
| 360 | { |
| 361 | SCLPDevice *sclp = SCLP(obj); |
| 362 | Object *new; |
| 363 | |
| 364 | new = object_new(TYPE_SCLP_EVENT_FACILITY); |
| 365 | object_property_add_child(obj, TYPE_SCLP_EVENT_FACILITY, new, NULL); |
David Hildenbrand | 515190d | 2015-05-27 09:49:43 +0200 | [diff] [blame] | 366 | object_unref(new); |
| 367 | sclp->event_facility = EVENT_FACILITY(new); |
David Hildenbrand | 1cf065f | 2015-05-29 13:53:08 +0200 | [diff] [blame] | 368 | |
| 369 | sclp_memory_init(sclp); |
David Hildenbrand | 515190d | 2015-05-27 09:49:43 +0200 | [diff] [blame] | 370 | } |
| 371 | |
| 372 | static void sclp_class_init(ObjectClass *oc, void *data) |
| 373 | { |
David Hildenbrand | 25a3c5a | 2015-05-27 10:04:56 +0200 | [diff] [blame] | 374 | SCLPDeviceClass *sc = SCLP_CLASS(oc); |
David Hildenbrand | 515190d | 2015-05-27 09:49:43 +0200 | [diff] [blame] | 375 | DeviceClass *dc = DEVICE_CLASS(oc); |
| 376 | |
| 377 | dc->desc = "SCLP (Service-Call Logical Processor)"; |
| 378 | dc->realize = sclp_realize; |
| 379 | dc->hotpluggable = false; |
| 380 | set_bit(DEVICE_CATEGORY_MISC, dc->categories); |
Thomas Huth | e6cb60b | 2017-10-04 15:53:19 +0200 | [diff] [blame] | 381 | /* |
| 382 | * Reason: Creates TYPE_SCLP_EVENT_FACILITY in sclp_init |
| 383 | * which is a non-pluggable sysbus device |
| 384 | */ |
| 385 | dc->user_creatable = false; |
David Hildenbrand | 25a3c5a | 2015-05-27 10:04:56 +0200 | [diff] [blame] | 386 | |
| 387 | sc->read_SCP_info = read_SCP_info; |
David Hildenbrand | 25a3c5a | 2015-05-27 10:04:56 +0200 | [diff] [blame] | 388 | sc->read_cpu_info = sclp_read_cpu_info; |
| 389 | sc->execute = sclp_execute; |
David Hildenbrand | 1723a1b | 2015-05-13 15:06:44 +0200 | [diff] [blame] | 390 | sc->service_interrupt = service_interrupt; |
David Hildenbrand | 515190d | 2015-05-27 09:49:43 +0200 | [diff] [blame] | 391 | } |
| 392 | |
| 393 | static TypeInfo sclp_info = { |
| 394 | .name = TYPE_SCLP, |
| 395 | .parent = TYPE_DEVICE, |
| 396 | .instance_init = sclp_init, |
| 397 | .instance_size = sizeof(SCLPDevice), |
| 398 | .class_init = sclp_class_init, |
| 399 | .class_size = sizeof(SCLPDeviceClass), |
| 400 | }; |
| 401 | |
Matthew Rosato | 0844df7 | 2014-08-28 11:25:32 -0400 | [diff] [blame] | 402 | static void register_types(void) |
| 403 | { |
David Hildenbrand | 515190d | 2015-05-27 09:49:43 +0200 | [diff] [blame] | 404 | type_register_static(&sclp_info); |
Matthew Rosato | 0844df7 | 2014-08-28 11:25:32 -0400 | [diff] [blame] | 405 | } |
| 406 | type_init(register_types); |