| 1 | /* |
| 2 | * s390x SIGP instruction handling |
| 3 | * |
| 4 | * Copyright (c) 2009 Alexander Graf <agraf@suse.de> |
| 5 | * Copyright IBM Corp. 2012 |
| 6 | * |
| 7 | * This work is licensed under the terms of the GNU GPL, version 2 or later. |
| 8 | * See the COPYING file in the top-level directory. |
| 9 | */ |
| 10 | |
| 11 | #include "qemu/osdep.h" |
| 12 | #include "cpu.h" |
| 13 | #include "s390x-internal.h" |
| 14 | #include "hw/core/boards.h" |
| 15 | #include "system/hw_accel.h" |
| 16 | #include "system/memory.h" |
| 17 | #include "system/runstate.h" |
| 18 | #include "system/address-spaces.h" |
| 19 | #include "exec/cputlb.h" |
| 20 | #include "system/tcg.h" |
| 21 | #include "trace.h" |
| 22 | #include "qapi/qapi-types-machine.h" |
| 23 | #include "target/s390x/kvm/pv.h" |
| 24 | |
| 25 | QemuMutex qemu_sigp_mutex; |
| 26 | |
| 27 | typedef struct SigpInfo { |
| 28 | uint64_t param; |
| 29 | int cc; |
| 30 | uint64_t *status_reg; |
| 31 | } SigpInfo; |
| 32 | |
| 33 | static void set_sigp_status(SigpInfo *si, uint64_t status) |
| 34 | { |
| 35 | *si->status_reg &= 0xffffffff00000000ULL; |
| 36 | *si->status_reg |= status; |
| 37 | si->cc = SIGP_CC_STATUS_STORED; |
| 38 | } |
| 39 | |
| 40 | static void sigp_sense(S390CPU *dst_cpu, SigpInfo *si) |
| 41 | { |
| 42 | uint8_t state = s390_cpu_get_state(dst_cpu); |
| 43 | bool ext_call = dst_cpu->env.pending_int & INTERRUPT_EXTERNAL_CALL; |
| 44 | uint64_t status = 0; |
| 45 | |
| 46 | if (!tcg_enabled()) { |
| 47 | /* handled in KVM */ |
| 48 | set_sigp_status(si, SIGP_STAT_INVALID_ORDER); |
| 49 | return; |
| 50 | } |
| 51 | |
| 52 | /* sensing without locks is racy, but it's the same for real hw */ |
| 53 | if (state != S390_CPU_STATE_STOPPED && !ext_call) { |
| 54 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; |
| 55 | } else { |
| 56 | if (ext_call) { |
| 57 | status |= SIGP_STAT_EXT_CALL_PENDING; |
| 58 | } |
| 59 | if (state == S390_CPU_STATE_STOPPED) { |
| 60 | status |= SIGP_STAT_STOPPED; |
| 61 | } |
| 62 | set_sigp_status(si, status); |
| 63 | } |
| 64 | } |
| 65 | |
| 66 | static void sigp_external_call(S390CPU *src_cpu, S390CPU *dst_cpu, SigpInfo *si) |
| 67 | { |
| 68 | int ret; |
| 69 | |
| 70 | if (!tcg_enabled()) { |
| 71 | /* handled in KVM */ |
| 72 | set_sigp_status(si, SIGP_STAT_INVALID_ORDER); |
| 73 | return; |
| 74 | } |
| 75 | |
| 76 | ret = cpu_inject_external_call(dst_cpu, src_cpu->env.core_id); |
| 77 | if (!ret) { |
| 78 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; |
| 79 | } else { |
| 80 | set_sigp_status(si, SIGP_STAT_EXT_CALL_PENDING); |
| 81 | } |
| 82 | } |
| 83 | |
| 84 | static void sigp_emergency(S390CPU *src_cpu, S390CPU *dst_cpu, SigpInfo *si) |
| 85 | { |
| 86 | if (!tcg_enabled()) { |
| 87 | /* handled in KVM */ |
| 88 | set_sigp_status(si, SIGP_STAT_INVALID_ORDER); |
| 89 | return; |
| 90 | } |
| 91 | |
| 92 | cpu_inject_emergency_signal(dst_cpu, src_cpu->env.core_id); |
| 93 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; |
| 94 | } |
| 95 | |
| 96 | static void sigp_start(CPUState *cs, run_on_cpu_data arg) |
| 97 | { |
| 98 | S390CPU *cpu = S390_CPU(cs); |
| 99 | SigpInfo *si = arg.host_ptr; |
| 100 | |
| 101 | if (s390_cpu_get_state(cpu) != S390_CPU_STATE_STOPPED) { |
| 102 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; |
| 103 | return; |
| 104 | } |
| 105 | |
| 106 | s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu); |
| 107 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; |
| 108 | } |
| 109 | |
| 110 | static void sigp_stop(CPUState *cs, run_on_cpu_data arg) |
| 111 | { |
| 112 | S390CPU *cpu = S390_CPU(cs); |
| 113 | SigpInfo *si = arg.host_ptr; |
| 114 | |
| 115 | if (s390_cpu_get_state(cpu) != S390_CPU_STATE_OPERATING) { |
| 116 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; |
| 117 | return; |
| 118 | } |
| 119 | |
| 120 | /* disabled wait - sleeping in user space */ |
| 121 | if (cs->halted) { |
| 122 | s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu); |
| 123 | } else { |
| 124 | /* execute the stop function */ |
| 125 | cpu->env.sigp_order = SIGP_STOP; |
| 126 | cpu_inject_stop(cpu); |
| 127 | } |
| 128 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; |
| 129 | } |
| 130 | |
| 131 | typedef struct SigpSaveArea { |
| 132 | uint64_t fprs[16]; /* 0x0000 */ |
| 133 | uint64_t grs[16]; /* 0x0080 */ |
| 134 | PSW psw; /* 0x0100 */ |
| 135 | uint8_t pad_0x0110[0x0118 - 0x0110]; /* 0x0110 */ |
| 136 | uint32_t prefix; /* 0x0118 */ |
| 137 | uint32_t fpc; /* 0x011c */ |
| 138 | uint8_t pad_0x0120[0x0124 - 0x0120]; /* 0x0120 */ |
| 139 | uint32_t todpr; /* 0x0124 */ |
| 140 | uint64_t cputm; /* 0x0128 */ |
| 141 | uint64_t ckc; /* 0x0130 */ |
| 142 | uint8_t pad_0x0138[0x0140 - 0x0138]; /* 0x0138 */ |
| 143 | uint32_t ars[16]; /* 0x0140 */ |
| 144 | uint64_t crs[16]; /* 0x0384 */ |
| 145 | } SigpSaveArea; |
| 146 | QEMU_BUILD_BUG_ON(sizeof(SigpSaveArea) != 512); |
| 147 | |
| 148 | #define S390_STORE_STATUS_DEF_ADDR offsetof(LowCore, floating_pt_save_area) |
| 149 | static int s390_store_status(S390CPU *cpu, hwaddr addr, bool store_arch) |
| 150 | { |
| 151 | const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED; |
| 152 | AddressSpace *as = CPU(cpu)->as; |
| 153 | SigpSaveArea *sa; |
| 154 | hwaddr len = sizeof(*sa); |
| 155 | int i; |
| 156 | |
| 157 | /* For PVMs storing will occur when this cpu enters SIE again */ |
| 158 | if (s390_is_pv()) { |
| 159 | return 0; |
| 160 | } |
| 161 | |
| 162 | sa = address_space_map(as, addr, &len, true, attrs); |
| 163 | if (!sa) { |
| 164 | return -EFAULT; |
| 165 | } |
| 166 | if (len != sizeof(*sa)) { |
| 167 | address_space_unmap(as, sa, len, true, 0); |
| 168 | return -EFAULT; |
| 169 | } |
| 170 | |
| 171 | if (store_arch) { |
| 172 | static const uint8_t ar_id = 1; |
| 173 | |
| 174 | address_space_stb(as, offsetof(LowCore, ar_access_id), |
| 175 | ar_id, attrs, NULL); |
| 176 | |
| 177 | } |
| 178 | for (i = 0; i < 16; ++i) { |
| 179 | sa->fprs[i] = cpu_to_be64(*get_freg(&cpu->env, i)); |
| 180 | } |
| 181 | for (i = 0; i < 16; ++i) { |
| 182 | sa->grs[i] = cpu_to_be64(cpu->env.regs[i]); |
| 183 | } |
| 184 | sa->psw.addr = cpu_to_be64(cpu->env.psw.addr); |
| 185 | sa->psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(&cpu->env)); |
| 186 | sa->prefix = cpu_to_be32(cpu->env.psa); |
| 187 | sa->fpc = cpu_to_be32(cpu->env.fpc); |
| 188 | sa->todpr = cpu_to_be32(cpu->env.todpr); |
| 189 | sa->cputm = cpu_to_be64(cpu->env.cputm); |
| 190 | sa->ckc = cpu_to_be64(cpu->env.ckc >> 8); |
| 191 | for (i = 0; i < 16; ++i) { |
| 192 | sa->ars[i] = cpu_to_be32(cpu->env.aregs[i]); |
| 193 | } |
| 194 | for (i = 0; i < 16; ++i) { |
| 195 | sa->crs[i] = cpu_to_be64(cpu->env.cregs[i]); |
| 196 | } |
| 197 | |
| 198 | address_space_unmap(as, sa, len, true, len); |
| 199 | |
| 200 | return 0; |
| 201 | } |
| 202 | |
| 203 | static void sigp_stop_and_store_status(CPUState *cs, run_on_cpu_data arg) |
| 204 | { |
| 205 | S390CPU *cpu = S390_CPU(cs); |
| 206 | SigpInfo *si = arg.host_ptr; |
| 207 | |
| 208 | /* disabled wait - sleeping in user space */ |
| 209 | if (s390_cpu_get_state(cpu) == S390_CPU_STATE_OPERATING && cs->halted) { |
| 210 | s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu); |
| 211 | } |
| 212 | |
| 213 | switch (s390_cpu_get_state(cpu)) { |
| 214 | case S390_CPU_STATE_OPERATING: |
| 215 | cpu->env.sigp_order = SIGP_STOP_STORE_STATUS; |
| 216 | cpu_inject_stop(cpu); |
| 217 | /* store will be performed in do_stop_interrupt() */ |
| 218 | break; |
| 219 | case S390_CPU_STATE_STOPPED: |
| 220 | /* already stopped, just store the status */ |
| 221 | cpu_synchronize_state(cs); |
| 222 | s390_store_status(cpu, S390_STORE_STATUS_DEF_ADDR, true); |
| 223 | break; |
| 224 | } |
| 225 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; |
| 226 | } |
| 227 | |
| 228 | static void sigp_store_status_at_address(CPUState *cs, run_on_cpu_data arg) |
| 229 | { |
| 230 | S390CPU *cpu = S390_CPU(cs); |
| 231 | SigpInfo *si = arg.host_ptr; |
| 232 | uint32_t address = si->param & 0x7ffffe00u; |
| 233 | |
| 234 | /* cpu has to be stopped */ |
| 235 | if (s390_cpu_get_state(cpu) != S390_CPU_STATE_STOPPED) { |
| 236 | set_sigp_status(si, SIGP_STAT_INCORRECT_STATE); |
| 237 | return; |
| 238 | } |
| 239 | |
| 240 | cpu_synchronize_state(cs); |
| 241 | |
| 242 | if (s390_store_status(cpu, address, false)) { |
| 243 | set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER); |
| 244 | return; |
| 245 | } |
| 246 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; |
| 247 | } |
| 248 | |
| 249 | typedef struct SigpAdtlSaveArea { |
| 250 | uint64_t vregs[32][2]; /* 0x0000 */ |
| 251 | uint8_t pad_0x0200[0x0400 - 0x0200]; /* 0x0200 */ |
| 252 | uint64_t gscb[4]; /* 0x0400 */ |
| 253 | uint8_t pad_0x0420[0x1000 - 0x0420]; /* 0x0420 */ |
| 254 | } SigpAdtlSaveArea; |
| 255 | QEMU_BUILD_BUG_ON(sizeof(SigpAdtlSaveArea) != 4096); |
| 256 | |
| 257 | #define ADTL_GS_MIN_SIZE 2048 /* minimal size of adtl save area for GS */ |
| 258 | static int s390_store_adtl_status(S390CPU *cpu, hwaddr addr, hwaddr len) |
| 259 | { |
| 260 | const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED; |
| 261 | AddressSpace *as = CPU(cpu)->as; |
| 262 | SigpAdtlSaveArea *sa; |
| 263 | hwaddr save = len; |
| 264 | int i; |
| 265 | |
| 266 | sa = address_space_map(as, addr, &save, true, attrs); |
| 267 | if (!sa) { |
| 268 | return -EFAULT; |
| 269 | } |
| 270 | if (save != len) { |
| 271 | address_space_unmap(as, sa, len, true, 0); |
| 272 | return -EFAULT; |
| 273 | } |
| 274 | |
| 275 | if (s390_has_feat(S390_FEAT_VECTOR)) { |
| 276 | for (i = 0; i < 32; i++) { |
| 277 | sa->vregs[i][0] = cpu_to_be64(cpu->env.vregs[i][0]); |
| 278 | sa->vregs[i][1] = cpu_to_be64(cpu->env.vregs[i][1]); |
| 279 | } |
| 280 | } |
| 281 | if (s390_has_feat(S390_FEAT_GUARDED_STORAGE) && len >= ADTL_GS_MIN_SIZE) { |
| 282 | for (i = 0; i < 4; i++) { |
| 283 | sa->gscb[i] = cpu_to_be64(cpu->env.gscb[i]); |
| 284 | } |
| 285 | } |
| 286 | |
| 287 | address_space_unmap(as, sa, len, true, len); |
| 288 | |
| 289 | return 0; |
| 290 | } |
| 291 | |
| 292 | #define ADTL_SAVE_LC_MASK 0xfUL |
| 293 | static void sigp_store_adtl_status(CPUState *cs, run_on_cpu_data arg) |
| 294 | { |
| 295 | S390CPU *cpu = S390_CPU(cs); |
| 296 | SigpInfo *si = arg.host_ptr; |
| 297 | uint8_t lc = si->param & ADTL_SAVE_LC_MASK; |
| 298 | hwaddr addr = si->param & ~ADTL_SAVE_LC_MASK; |
| 299 | hwaddr len = 1UL << (lc ? lc : 10); |
| 300 | |
| 301 | if (!s390_has_feat(S390_FEAT_VECTOR) && |
| 302 | !s390_has_feat(S390_FEAT_GUARDED_STORAGE)) { |
| 303 | set_sigp_status(si, SIGP_STAT_INVALID_ORDER); |
| 304 | return; |
| 305 | } |
| 306 | |
| 307 | /* cpu has to be stopped */ |
| 308 | if (s390_cpu_get_state(cpu) != S390_CPU_STATE_STOPPED) { |
| 309 | set_sigp_status(si, SIGP_STAT_INCORRECT_STATE); |
| 310 | return; |
| 311 | } |
| 312 | |
| 313 | /* address must be aligned to length */ |
| 314 | if (addr & (len - 1)) { |
| 315 | set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER); |
| 316 | return; |
| 317 | } |
| 318 | |
| 319 | /* no GS: only lc == 0 is valid */ |
| 320 | if (!s390_has_feat(S390_FEAT_GUARDED_STORAGE) && |
| 321 | lc != 0) { |
| 322 | set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER); |
| 323 | return; |
| 324 | } |
| 325 | |
| 326 | /* GS: 0, 10, 11, 12 are valid */ |
| 327 | if (s390_has_feat(S390_FEAT_GUARDED_STORAGE) && |
| 328 | lc != 0 && |
| 329 | lc != 10 && |
| 330 | lc != 11 && |
| 331 | lc != 12) { |
| 332 | set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER); |
| 333 | return; |
| 334 | } |
| 335 | |
| 336 | cpu_synchronize_state(cs); |
| 337 | |
| 338 | if (s390_store_adtl_status(cpu, addr, len)) { |
| 339 | set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER); |
| 340 | return; |
| 341 | } |
| 342 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; |
| 343 | } |
| 344 | |
| 345 | static void sigp_restart(CPUState *cs, run_on_cpu_data arg) |
| 346 | { |
| 347 | S390CPU *cpu = S390_CPU(cs); |
| 348 | SigpInfo *si = arg.host_ptr; |
| 349 | |
| 350 | switch (s390_cpu_get_state(cpu)) { |
| 351 | case S390_CPU_STATE_STOPPED: |
| 352 | /* the restart irq has to be delivered prior to any other pending irq */ |
| 353 | cpu_synchronize_state(cs); |
| 354 | /* |
| 355 | * Set OPERATING (and unhalting) before loading the restart PSW. |
| 356 | * s390_cpu_set_psw() will then properly halt the CPU again if |
| 357 | * necessary (TCG). |
| 358 | */ |
| 359 | s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu); |
| 360 | do_restart_interrupt(&cpu->env); |
| 361 | break; |
| 362 | case S390_CPU_STATE_OPERATING: |
| 363 | cpu_inject_restart(cpu); |
| 364 | break; |
| 365 | } |
| 366 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; |
| 367 | } |
| 368 | |
| 369 | static void sigp_initial_cpu_reset(CPUState *cs, run_on_cpu_data arg) |
| 370 | { |
| 371 | SigpInfo *si = arg.host_ptr; |
| 372 | |
| 373 | cpu_synchronize_state(cs); |
| 374 | resettable_reset(OBJECT(cs), RESET_TYPE_S390_CPU_INITIAL); |
| 375 | cpu_synchronize_post_reset(cs); |
| 376 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; |
| 377 | } |
| 378 | |
| 379 | static void sigp_cpu_reset(CPUState *cs, run_on_cpu_data arg) |
| 380 | { |
| 381 | SigpInfo *si = arg.host_ptr; |
| 382 | |
| 383 | cpu_synchronize_state(cs); |
| 384 | resettable_reset(OBJECT(cs), RESET_TYPE_S390_CPU_NORMAL); |
| 385 | cpu_synchronize_post_reset(cs); |
| 386 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; |
| 387 | } |
| 388 | |
| 389 | static void sigp_set_prefix(CPUState *cs, run_on_cpu_data arg) |
| 390 | { |
| 391 | S390CPU *cpu = S390_CPU(cs); |
| 392 | SigpInfo *si = arg.host_ptr; |
| 393 | uint32_t addr = si->param & 0x7fffe000u; |
| 394 | |
| 395 | cpu_synchronize_state(cs); |
| 396 | |
| 397 | if (!address_space_access_valid(&address_space_memory, addr, |
| 398 | sizeof(struct LowCore), false, |
| 399 | MEMTXATTRS_UNSPECIFIED)) { |
| 400 | set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER); |
| 401 | return; |
| 402 | } |
| 403 | |
| 404 | /* cpu has to be stopped */ |
| 405 | if (s390_cpu_get_state(cpu) != S390_CPU_STATE_STOPPED) { |
| 406 | set_sigp_status(si, SIGP_STAT_INCORRECT_STATE); |
| 407 | return; |
| 408 | } |
| 409 | |
| 410 | cpu->env.psa = addr; |
| 411 | tlb_flush(cs); |
| 412 | cpu_synchronize_post_init(cs); |
| 413 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; |
| 414 | } |
| 415 | |
| 416 | static void sigp_cond_emergency(S390CPU *src_cpu, S390CPU *dst_cpu, |
| 417 | SigpInfo *si) |
| 418 | { |
| 419 | const uint64_t psw_int_mask = PSW_MASK_IO | PSW_MASK_EXT; |
| 420 | uint16_t p_asn, s_asn, asn; |
| 421 | uint64_t psw_addr, psw_mask; |
| 422 | bool idle; |
| 423 | |
| 424 | if (!tcg_enabled()) { |
| 425 | /* handled in KVM */ |
| 426 | set_sigp_status(si, SIGP_STAT_INVALID_ORDER); |
| 427 | return; |
| 428 | } |
| 429 | |
| 430 | /* this looks racy, but these values are only used when STOPPED */ |
| 431 | idle = CPU(dst_cpu)->halted; |
| 432 | psw_addr = dst_cpu->env.psw.addr; |
| 433 | psw_mask = dst_cpu->env.psw.mask; |
| 434 | asn = si->param; |
| 435 | p_asn = dst_cpu->env.cregs[4] & 0xffff; /* Primary ASN */ |
| 436 | s_asn = dst_cpu->env.cregs[3] & 0xffff; /* Secondary ASN */ |
| 437 | |
| 438 | if (s390_cpu_get_state(dst_cpu) != S390_CPU_STATE_STOPPED || |
| 439 | (psw_mask & psw_int_mask) != psw_int_mask || |
| 440 | (idle && psw_addr != 0) || |
| 441 | (!idle && (asn == p_asn || asn == s_asn))) { |
| 442 | cpu_inject_emergency_signal(dst_cpu, src_cpu->env.core_id); |
| 443 | } else { |
| 444 | set_sigp_status(si, SIGP_STAT_INCORRECT_STATE); |
| 445 | } |
| 446 | |
| 447 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; |
| 448 | } |
| 449 | |
| 450 | static void sigp_sense_running(S390CPU *dst_cpu, SigpInfo *si) |
| 451 | { |
| 452 | if (!tcg_enabled()) { |
| 453 | /* handled in KVM */ |
| 454 | set_sigp_status(si, SIGP_STAT_INVALID_ORDER); |
| 455 | return; |
| 456 | } |
| 457 | |
| 458 | /* sensing without locks is racy, but it's the same for real hw */ |
| 459 | if (!s390_has_feat(S390_FEAT_SENSE_RUNNING_STATUS)) { |
| 460 | set_sigp_status(si, SIGP_STAT_INVALID_ORDER); |
| 461 | return; |
| 462 | } |
| 463 | |
| 464 | /* If halted (which includes also STOPPED), it is not running */ |
| 465 | if (CPU(dst_cpu)->halted) { |
| 466 | set_sigp_status(si, SIGP_STAT_NOT_RUNNING); |
| 467 | } else { |
| 468 | si->cc = SIGP_CC_ORDER_CODE_ACCEPTED; |
| 469 | } |
| 470 | } |
| 471 | |
| 472 | static int handle_sigp_single_dst(S390CPU *cpu, S390CPU *dst_cpu, uint8_t order, |
| 473 | uint64_t param, uint64_t *status_reg) |
| 474 | { |
| 475 | SigpInfo si = { |
| 476 | .param = param, |
| 477 | .status_reg = status_reg, |
| 478 | }; |
| 479 | |
| 480 | /* cpu available? */ |
| 481 | if (dst_cpu == NULL) { |
| 482 | return SIGP_CC_NOT_OPERATIONAL; |
| 483 | } |
| 484 | |
| 485 | /* only resets can break pending orders */ |
| 486 | if (dst_cpu->env.sigp_order != 0 && |
| 487 | order != SIGP_CPU_RESET && |
| 488 | order != SIGP_INITIAL_CPU_RESET) { |
| 489 | return SIGP_CC_BUSY; |
| 490 | } |
| 491 | |
| 492 | switch (order) { |
| 493 | case SIGP_SENSE: |
| 494 | sigp_sense(dst_cpu, &si); |
| 495 | break; |
| 496 | case SIGP_EXTERNAL_CALL: |
| 497 | sigp_external_call(cpu, dst_cpu, &si); |
| 498 | break; |
| 499 | case SIGP_EMERGENCY: |
| 500 | sigp_emergency(cpu, dst_cpu, &si); |
| 501 | break; |
| 502 | case SIGP_START: |
| 503 | run_on_cpu(CPU(dst_cpu), sigp_start, RUN_ON_CPU_HOST_PTR(&si)); |
| 504 | break; |
| 505 | case SIGP_STOP: |
| 506 | run_on_cpu(CPU(dst_cpu), sigp_stop, RUN_ON_CPU_HOST_PTR(&si)); |
| 507 | break; |
| 508 | case SIGP_RESTART: |
| 509 | run_on_cpu(CPU(dst_cpu), sigp_restart, RUN_ON_CPU_HOST_PTR(&si)); |
| 510 | break; |
| 511 | case SIGP_STOP_STORE_STATUS: |
| 512 | run_on_cpu(CPU(dst_cpu), sigp_stop_and_store_status, RUN_ON_CPU_HOST_PTR(&si)); |
| 513 | break; |
| 514 | case SIGP_STORE_STATUS_ADDR: |
| 515 | run_on_cpu(CPU(dst_cpu), sigp_store_status_at_address, RUN_ON_CPU_HOST_PTR(&si)); |
| 516 | break; |
| 517 | case SIGP_STORE_ADTL_STATUS: |
| 518 | run_on_cpu(CPU(dst_cpu), sigp_store_adtl_status, RUN_ON_CPU_HOST_PTR(&si)); |
| 519 | break; |
| 520 | case SIGP_SET_PREFIX: |
| 521 | run_on_cpu(CPU(dst_cpu), sigp_set_prefix, RUN_ON_CPU_HOST_PTR(&si)); |
| 522 | break; |
| 523 | case SIGP_INITIAL_CPU_RESET: |
| 524 | run_on_cpu(CPU(dst_cpu), sigp_initial_cpu_reset, RUN_ON_CPU_HOST_PTR(&si)); |
| 525 | break; |
| 526 | case SIGP_CPU_RESET: |
| 527 | run_on_cpu(CPU(dst_cpu), sigp_cpu_reset, RUN_ON_CPU_HOST_PTR(&si)); |
| 528 | break; |
| 529 | case SIGP_COND_EMERGENCY: |
| 530 | sigp_cond_emergency(cpu, dst_cpu, &si); |
| 531 | break; |
| 532 | case SIGP_SENSE_RUNNING: |
| 533 | sigp_sense_running(dst_cpu, &si); |
| 534 | break; |
| 535 | default: |
| 536 | set_sigp_status(&si, SIGP_STAT_INVALID_ORDER); |
| 537 | } |
| 538 | |
| 539 | return si.cc; |
| 540 | } |
| 541 | |
| 542 | static int sigp_set_architecture(S390CPU *cpu, uint32_t param, |
| 543 | uint64_t *status_reg) |
| 544 | { |
| 545 | *status_reg &= 0xffffffff00000000ULL; |
| 546 | |
| 547 | /* Reject set arch order, with czam we're always in z/Arch mode. */ |
| 548 | *status_reg |= SIGP_STAT_INVALID_PARAMETER; |
| 549 | return SIGP_CC_STATUS_STORED; |
| 550 | } |
| 551 | |
| 552 | S390CPU *s390_cpu_addr2state(uint16_t cpu_addr) |
| 553 | { |
| 554 | static MachineState *ms; |
| 555 | |
| 556 | if (!ms) { |
| 557 | ms = MACHINE(qdev_get_machine()); |
| 558 | g_assert(ms->possible_cpus); |
| 559 | } |
| 560 | |
| 561 | /* CPU address corresponds to the core_id and the index */ |
| 562 | if (cpu_addr >= ms->possible_cpus->len) { |
| 563 | return NULL; |
| 564 | } |
| 565 | return S390_CPU(ms->possible_cpus->cpus[cpu_addr].cpu); |
| 566 | } |
| 567 | |
| 568 | int handle_sigp(CPUS390XState *env, uint8_t order, uint64_t r1, uint64_t r3) |
| 569 | { |
| 570 | uint64_t *status_reg = &env->regs[r1]; |
| 571 | uint64_t param = (r1 % 2) ? env->regs[r1] : env->regs[r1 + 1]; |
| 572 | S390CPU *cpu = env_archcpu(env); |
| 573 | S390CPU *dst_cpu = NULL; |
| 574 | int ret; |
| 575 | |
| 576 | if (qemu_mutex_trylock(&qemu_sigp_mutex)) { |
| 577 | ret = SIGP_CC_BUSY; |
| 578 | goto out; |
| 579 | } |
| 580 | |
| 581 | switch (order) { |
| 582 | case SIGP_SET_ARCH: |
| 583 | ret = sigp_set_architecture(cpu, param, status_reg); |
| 584 | break; |
| 585 | default: |
| 586 | /* all other sigp orders target a single vcpu */ |
| 587 | dst_cpu = s390_cpu_addr2state(env->regs[r3]); |
| 588 | ret = handle_sigp_single_dst(cpu, dst_cpu, order, param, status_reg); |
| 589 | } |
| 590 | qemu_mutex_unlock(&qemu_sigp_mutex); |
| 591 | |
| 592 | out: |
| 593 | trace_sigp_finished(order, CPU(cpu)->cpu_index, |
| 594 | dst_cpu ? CPU(dst_cpu)->cpu_index : -1, ret); |
| 595 | g_assert(ret >= 0); |
| 596 | |
| 597 | return ret; |
| 598 | } |
| 599 | |
| 600 | int s390_cpu_restart(S390CPU *cpu) |
| 601 | { |
| 602 | SigpInfo si = {}; |
| 603 | |
| 604 | run_on_cpu(CPU(cpu), sigp_restart, RUN_ON_CPU_HOST_PTR(&si)); |
| 605 | return 0; |
| 606 | } |
| 607 | |
| 608 | void do_stop_interrupt(CPUS390XState *env) |
| 609 | { |
| 610 | S390CPU *cpu = env_archcpu(env); |
| 611 | |
| 612 | /* |
| 613 | * Complete the STOP operation before exposing the CPU as |
| 614 | * STOPPED to the system. |
| 615 | */ |
| 616 | if (cpu->env.sigp_order == SIGP_STOP_STORE_STATUS) { |
| 617 | s390_store_status(cpu, S390_STORE_STATUS_DEF_ADDR, true); |
| 618 | } |
| 619 | env->sigp_order = 0; |
| 620 | if (s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu) == 0) { |
| 621 | qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); |
| 622 | } |
| 623 | env->pending_int &= ~INTERRUPT_STOP; |
| 624 | } |
| 625 | |
| 626 | void s390_init_sigp(void) |
| 627 | { |
| 628 | qemu_mutex_init(&qemu_sigp_mutex); |
| 629 | } |