110ec5117SAlexander Graf /* 2aea1e885SBlue Swirl * S/390 misc helper routines 310ec5117SAlexander Graf * 4defb0e31SAlexander Graf * Copyright (c) 2009 Ulrich Hecht 510ec5117SAlexander Graf * Copyright (c) 2009 Alexander Graf 610ec5117SAlexander Graf * 710ec5117SAlexander Graf * This library is free software; you can redistribute it and/or 810ec5117SAlexander Graf * modify it under the terms of the GNU Lesser General Public 910ec5117SAlexander Graf * License as published by the Free Software Foundation; either 1010ec5117SAlexander Graf * version 2 of the License, or (at your option) any later version. 1110ec5117SAlexander Graf * 1210ec5117SAlexander Graf * This library is distributed in the hope that it will be useful, 1310ec5117SAlexander Graf * but WITHOUT ANY WARRANTY; without even the implied warranty of 1410ec5117SAlexander Graf * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1510ec5117SAlexander Graf * Lesser General Public License for more details. 1610ec5117SAlexander Graf * 1710ec5117SAlexander Graf * You should have received a copy of the GNU Lesser General Public 1870539e18SBlue Swirl * License along with this library; if not, see <http://www.gnu.org/licenses/>. 1910ec5117SAlexander Graf */ 2010ec5117SAlexander Graf 213e457172SBlue Swirl #include "cpu.h" 22022c62cbSPaolo Bonzini #include "exec/memory.h" 231de7afc9SPaolo Bonzini #include "qemu/host-utils.h" 242ef6175aSRichard Henderson #include "exec/helper-proto.h" 25defb0e31SAlexander Graf #include <string.h> 269c17d615SPaolo Bonzini #include "sysemu/kvm.h" 271de7afc9SPaolo Bonzini #include "qemu/timer.h" 28df75a4e2SFan Zhang #include "exec/address-spaces.h" 29af2be207SJan Kiszka #ifdef CONFIG_KVM 30af2be207SJan Kiszka #include <linux/kvm.h> 31af2be207SJan Kiszka #endif 32f08b6170SPaolo Bonzini #include "exec/cpu_ldst.h" 338fc639afSXu Wang #include "hw/watchdog/wdt_diag288.h" 3410ec5117SAlexander Graf 351864b94aSAlexander Graf #if !defined(CONFIG_USER_ONLY) 36f0778475SChristian Borntraeger #include "sysemu/cpus.h" 379c17d615SPaolo Bonzini #include "sysemu/sysemu.h" 3840fa5264SHeinz Graalfs #include "hw/s390x/ebcdic.h" 39df75a4e2SFan Zhang #include "hw/s390x/ipl.h" 4010ec5117SAlexander Graf #endif 41d5a43964SAlexander Graf 42defb0e31SAlexander Graf /* #define DEBUG_HELPER */ 43defb0e31SAlexander Graf #ifdef DEBUG_HELPER 44defb0e31SAlexander Graf #define HELPER_LOG(x...) qemu_log(x) 45defb0e31SAlexander Graf #else 46defb0e31SAlexander Graf #define HELPER_LOG(x...) 47defb0e31SAlexander Graf #endif 48defb0e31SAlexander Graf 49b4e2bd35SRichard Henderson /* Raise an exception dynamically from a helper function. */ 50b4e2bd35SRichard Henderson void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp, 51b4e2bd35SRichard Henderson uintptr_t retaddr) 52b4e2bd35SRichard Henderson { 5327103424SAndreas Färber CPUState *cs = CPU(s390_env_get_cpu(env)); 54b4e2bd35SRichard Henderson int t; 55b4e2bd35SRichard Henderson 5627103424SAndreas Färber cs->exception_index = EXCP_PGM; 57b4e2bd35SRichard Henderson env->int_pgm_code = excp; 58b4e2bd35SRichard Henderson 59b4e2bd35SRichard Henderson /* Use the (ultimate) callers address to find the insn that trapped. */ 603f38f309SAndreas Färber cpu_restore_state(cs, retaddr); 61b4e2bd35SRichard Henderson 62b4e2bd35SRichard Henderson /* Advance past the insn. */ 63b4e2bd35SRichard Henderson t = cpu_ldub_code(env, env->psw.addr); 64b4e2bd35SRichard Henderson env->int_pgm_ilen = t = get_ilen(t); 659bebf986SAurelien Jarno env->psw.addr += t; 66b4e2bd35SRichard Henderson 675638d180SAndreas Färber cpu_loop_exit(cs); 68b4e2bd35SRichard Henderson } 69b4e2bd35SRichard Henderson 70d5a103cdSRichard Henderson /* Raise an exception statically from a TB. */ 71089f5c06SBlue Swirl void HELPER(exception)(CPUS390XState *env, uint32_t excp) 72defb0e31SAlexander Graf { 7327103424SAndreas Färber CPUState *cs = CPU(s390_env_get_cpu(env)); 7427103424SAndreas Färber 7571e47088SBlue Swirl HELPER_LOG("%s: exception %d\n", __func__, excp); 7627103424SAndreas Färber cs->exception_index = excp; 775638d180SAndreas Färber cpu_loop_exit(cs); 78defb0e31SAlexander Graf } 79defb0e31SAlexander Graf 80defb0e31SAlexander Graf #ifndef CONFIG_USER_ONLY 81a158986dSStefan Weil 82d5a103cdSRichard Henderson void program_interrupt(CPUS390XState *env, uint32_t code, int ilen) 83defb0e31SAlexander Graf { 8427103424SAndreas Färber S390CPU *cpu = s390_env_get_cpu(env); 8527103424SAndreas Färber 860d404541SRichard Henderson qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n", 870d404541SRichard Henderson env->psw.addr); 88defb0e31SAlexander Graf 89defb0e31SAlexander Graf if (kvm_enabled()) { 90af2be207SJan Kiszka #ifdef CONFIG_KVM 91de13d216SCornelia Huck struct kvm_s390_irq irq = { 92de13d216SCornelia Huck .type = KVM_S390_PROGRAM_INT, 93de13d216SCornelia Huck .u.pgm.code = code, 94de13d216SCornelia Huck }; 95de13d216SCornelia Huck 96de13d216SCornelia Huck kvm_s390_vcpu_interrupt(cpu, &irq); 97af2be207SJan Kiszka #endif 98defb0e31SAlexander Graf } else { 9927103424SAndreas Färber CPUState *cs = CPU(cpu); 10027103424SAndreas Färber 101defb0e31SAlexander Graf env->int_pgm_code = code; 102d5a103cdSRichard Henderson env->int_pgm_ilen = ilen; 10327103424SAndreas Färber cs->exception_index = EXCP_PGM; 1045638d180SAndreas Färber cpu_loop_exit(cs); 105defb0e31SAlexander Graf } 106defb0e31SAlexander Graf } 107defb0e31SAlexander Graf 108defb0e31SAlexander Graf /* SCLP service call */ 109dc458df9SRichard Henderson uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2) 110defb0e31SAlexander Graf { 1116e252802SThomas Huth int r = sclp_service_call(env, r1, r2); 1129abf567dSChristian Borntraeger if (r < 0) { 1139abf567dSChristian Borntraeger program_interrupt(env, -r, 4); 114d5a43964SAlexander Graf return 0; 115d5a43964SAlexander Graf } 1169abf567dSChristian Borntraeger return r; 1179abf567dSChristian Borntraeger } 118defb0e31SAlexander Graf 119268846baSEugene (jno) Dvurechenski #ifndef CONFIG_USER_ONLY 120d8b30c83SChristian Borntraeger static int modified_clear_reset(S390CPU *cpu) 121d8b30c83SChristian Borntraeger { 122d8b30c83SChristian Borntraeger S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); 12385ca3371SDavid Hildenbrand CPUState *t; 124d8b30c83SChristian Borntraeger 125d8b30c83SChristian Borntraeger pause_all_vcpus(); 126d8b30c83SChristian Borntraeger cpu_synchronize_all_states(); 12785ca3371SDavid Hildenbrand CPU_FOREACH(t) { 12885ca3371SDavid Hildenbrand run_on_cpu(t, s390_do_cpu_full_reset, t); 12985ca3371SDavid Hildenbrand } 1304cb88c3cSDominik Dingel cmma_reset(cpu); 131d8b30c83SChristian Borntraeger io_subsystem_reset(); 132d8b30c83SChristian Borntraeger scc->load_normal(CPU(cpu)); 133d8b30c83SChristian Borntraeger cpu_synchronize_all_post_reset(); 134d8b30c83SChristian Borntraeger resume_all_vcpus(); 135d8b30c83SChristian Borntraeger return 0; 136d8b30c83SChristian Borntraeger } 137d8b30c83SChristian Borntraeger 138f0778475SChristian Borntraeger static int load_normal_reset(S390CPU *cpu) 139f0778475SChristian Borntraeger { 140f0778475SChristian Borntraeger S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); 14185ca3371SDavid Hildenbrand CPUState *t; 142f0778475SChristian Borntraeger 143f0778475SChristian Borntraeger pause_all_vcpus(); 144f0778475SChristian Borntraeger cpu_synchronize_all_states(); 14585ca3371SDavid Hildenbrand CPU_FOREACH(t) { 14685ca3371SDavid Hildenbrand run_on_cpu(t, s390_do_cpu_reset, t); 14785ca3371SDavid Hildenbrand } 1484cb88c3cSDominik Dingel cmma_reset(cpu); 149f0778475SChristian Borntraeger io_subsystem_reset(); 150f0778475SChristian Borntraeger scc->initial_cpu_reset(CPU(cpu)); 151f0778475SChristian Borntraeger scc->load_normal(CPU(cpu)); 152f0778475SChristian Borntraeger cpu_synchronize_all_post_reset(); 153f0778475SChristian Borntraeger resume_all_vcpus(); 154f0778475SChristian Borntraeger return 0; 155f0778475SChristian Borntraeger } 156f0778475SChristian Borntraeger 1578fc639afSXu Wang int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3) 1588fc639afSXu Wang { 1598fc639afSXu Wang uint64_t func = env->regs[r1]; 1608fc639afSXu Wang uint64_t timeout = env->regs[r1 + 1]; 1618fc639afSXu Wang uint64_t action = env->regs[r3]; 1628fc639afSXu Wang Object *obj; 1638fc639afSXu Wang DIAG288State *diag288; 1648fc639afSXu Wang DIAG288Class *diag288_class; 1658fc639afSXu Wang 1668fc639afSXu Wang if (r1 % 2 || action != 0) { 1678fc639afSXu Wang return -1; 1688fc639afSXu Wang } 1698fc639afSXu Wang 1708fc639afSXu Wang /* Timeout must be more than 15 seconds except for timer deletion */ 1718fc639afSXu Wang if (func != WDT_DIAG288_CANCEL && timeout < 15) { 1728fc639afSXu Wang return -1; 1738fc639afSXu Wang } 1748fc639afSXu Wang 1758fc639afSXu Wang obj = object_resolve_path_type("", TYPE_WDT_DIAG288, NULL); 1768fc639afSXu Wang if (!obj) { 1778fc639afSXu Wang return -1; 1788fc639afSXu Wang } 1798fc639afSXu Wang 1808fc639afSXu Wang diag288 = DIAG288(obj); 1818fc639afSXu Wang diag288_class = DIAG288_GET_CLASS(diag288); 1828fc639afSXu Wang return diag288_class->handle_timer(diag288, func, timeout); 1838fc639afSXu Wang } 1848fc639afSXu Wang 185df75a4e2SFan Zhang #define DIAG_308_RC_OK 0x0001 186268846baSEugene (jno) Dvurechenski #define DIAG_308_RC_NO_CONF 0x0102 187268846baSEugene (jno) Dvurechenski #define DIAG_308_RC_INVALID 0x0402 188df75a4e2SFan Zhang 189268846baSEugene (jno) Dvurechenski void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3) 190268846baSEugene (jno) Dvurechenski { 191268846baSEugene (jno) Dvurechenski uint64_t addr = env->regs[r1]; 192268846baSEugene (jno) Dvurechenski uint64_t subcode = env->regs[r3]; 193df75a4e2SFan Zhang IplParameterBlock *iplb; 194268846baSEugene (jno) Dvurechenski 195268846baSEugene (jno) Dvurechenski if (env->psw.mask & PSW_MASK_PSTATE) { 196268846baSEugene (jno) Dvurechenski program_interrupt(env, PGM_PRIVILEGED, ILEN_LATER_INC); 197268846baSEugene (jno) Dvurechenski return; 198268846baSEugene (jno) Dvurechenski } 199268846baSEugene (jno) Dvurechenski 200268846baSEugene (jno) Dvurechenski if ((subcode & ~0x0ffffULL) || (subcode > 6)) { 201268846baSEugene (jno) Dvurechenski program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC); 202268846baSEugene (jno) Dvurechenski return; 203268846baSEugene (jno) Dvurechenski } 204268846baSEugene (jno) Dvurechenski 205268846baSEugene (jno) Dvurechenski switch (subcode) { 206d8b30c83SChristian Borntraeger case 0: 207d8b30c83SChristian Borntraeger modified_clear_reset(s390_env_get_cpu(env)); 2088df7eef3SAurelien Jarno if (tcg_enabled()) { 2098df7eef3SAurelien Jarno cpu_loop_exit(CPU(s390_env_get_cpu(env))); 2108df7eef3SAurelien Jarno } 211d8b30c83SChristian Borntraeger break; 212f0778475SChristian Borntraeger case 1: 213f0778475SChristian Borntraeger load_normal_reset(s390_env_get_cpu(env)); 2148df7eef3SAurelien Jarno if (tcg_enabled()) { 2158df7eef3SAurelien Jarno cpu_loop_exit(CPU(s390_env_get_cpu(env))); 2168df7eef3SAurelien Jarno } 217f0778475SChristian Borntraeger break; 2182ecacb0bSAurelien Jarno case 3: 2192ecacb0bSAurelien Jarno s390_reipl_request(); 2202ecacb0bSAurelien Jarno if (tcg_enabled()) { 2212ecacb0bSAurelien Jarno cpu_loop_exit(CPU(s390_env_get_cpu(env))); 2222ecacb0bSAurelien Jarno } 2232ecacb0bSAurelien Jarno break; 224268846baSEugene (jno) Dvurechenski case 5: 225268846baSEugene (jno) Dvurechenski if ((r1 & 1) || (addr & 0x0fffULL)) { 226268846baSEugene (jno) Dvurechenski program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC); 227268846baSEugene (jno) Dvurechenski return; 228268846baSEugene (jno) Dvurechenski } 229df75a4e2SFan Zhang if (!address_space_access_valid(&address_space_memory, addr, 230df75a4e2SFan Zhang sizeof(IplParameterBlock), false)) { 231df75a4e2SFan Zhang program_interrupt(env, PGM_ADDRESSING, ILEN_LATER_INC); 232df75a4e2SFan Zhang return; 233df75a4e2SFan Zhang } 234df75a4e2SFan Zhang iplb = g_malloc0(sizeof(struct IplParameterBlock)); 235df75a4e2SFan Zhang cpu_physical_memory_read(addr, iplb, sizeof(struct IplParameterBlock)); 236df75a4e2SFan Zhang if (!s390_ipl_update_diag308(iplb)) { 237df75a4e2SFan Zhang env->regs[r1 + 1] = DIAG_308_RC_OK; 238df75a4e2SFan Zhang } else { 239268846baSEugene (jno) Dvurechenski env->regs[r1 + 1] = DIAG_308_RC_INVALID; 240df75a4e2SFan Zhang } 241df75a4e2SFan Zhang g_free(iplb); 242268846baSEugene (jno) Dvurechenski return; 243268846baSEugene (jno) Dvurechenski case 6: 244268846baSEugene (jno) Dvurechenski if ((r1 & 1) || (addr & 0x0fffULL)) { 245268846baSEugene (jno) Dvurechenski program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC); 246268846baSEugene (jno) Dvurechenski return; 247268846baSEugene (jno) Dvurechenski } 248df75a4e2SFan Zhang if (!address_space_access_valid(&address_space_memory, addr, 249df75a4e2SFan Zhang sizeof(IplParameterBlock), true)) { 250df75a4e2SFan Zhang program_interrupt(env, PGM_ADDRESSING, ILEN_LATER_INC); 251df75a4e2SFan Zhang return; 252df75a4e2SFan Zhang } 253df75a4e2SFan Zhang iplb = s390_ipl_get_iplb(); 254df75a4e2SFan Zhang if (iplb) { 255df75a4e2SFan Zhang cpu_physical_memory_write(addr, iplb, 256df75a4e2SFan Zhang sizeof(struct IplParameterBlock)); 257df75a4e2SFan Zhang env->regs[r1 + 1] = DIAG_308_RC_OK; 258df75a4e2SFan Zhang } else { 259268846baSEugene (jno) Dvurechenski env->regs[r1 + 1] = DIAG_308_RC_NO_CONF; 260df75a4e2SFan Zhang } 261268846baSEugene (jno) Dvurechenski return; 262268846baSEugene (jno) Dvurechenski default: 263268846baSEugene (jno) Dvurechenski hw_error("Unhandled diag308 subcode %" PRIx64, subcode); 264268846baSEugene (jno) Dvurechenski break; 265268846baSEugene (jno) Dvurechenski } 266268846baSEugene (jno) Dvurechenski } 267268846baSEugene (jno) Dvurechenski #endif 268268846baSEugene (jno) Dvurechenski 2698df7eef3SAurelien Jarno void HELPER(diag)(CPUS390XState *env, uint32_t r1, uint32_t r3, uint32_t num) 270defb0e31SAlexander Graf { 271defb0e31SAlexander Graf uint64_t r; 272defb0e31SAlexander Graf 273defb0e31SAlexander Graf switch (num) { 274defb0e31SAlexander Graf case 0x500: 275defb0e31SAlexander Graf /* KVM hypercall */ 27628e942f8SCornelia Huck r = s390_virtio_hypercall(env); 277defb0e31SAlexander Graf break; 278defb0e31SAlexander Graf case 0x44: 279defb0e31SAlexander Graf /* yield */ 280defb0e31SAlexander Graf r = 0; 281defb0e31SAlexander Graf break; 282defb0e31SAlexander Graf case 0x308: 283defb0e31SAlexander Graf /* ipl */ 2848df7eef3SAurelien Jarno handle_diag_308(env, r1, r3); 285defb0e31SAlexander Graf r = 0; 286defb0e31SAlexander Graf break; 287defb0e31SAlexander Graf default: 288defb0e31SAlexander Graf r = -1; 289defb0e31SAlexander Graf break; 290defb0e31SAlexander Graf } 291defb0e31SAlexander Graf 292defb0e31SAlexander Graf if (r) { 293d5a103cdSRichard Henderson program_interrupt(env, PGM_OPERATION, ILEN_LATER_INC); 294defb0e31SAlexander Graf } 295defb0e31SAlexander Graf } 296defb0e31SAlexander Graf 297defb0e31SAlexander Graf /* Set Prefix */ 298089f5c06SBlue Swirl void HELPER(spx)(CPUS390XState *env, uint64_t a1) 299defb0e31SAlexander Graf { 30031b030d4SAndreas Färber CPUState *cs = CPU(s390_env_get_cpu(env)); 301e805a0d3SRichard Henderson uint32_t prefix = a1 & 0x7fffe000; 30231b030d4SAndreas Färber 303e805a0d3SRichard Henderson env->psa = prefix; 304defb0e31SAlexander Graf qemu_log("prefix: %#x\n", prefix); 30531b030d4SAndreas Färber tlb_flush_page(cs, 0); 30631b030d4SAndreas Färber tlb_flush_page(cs, TARGET_PAGE_SIZE); 307defb0e31SAlexander Graf } 308defb0e31SAlexander Graf 309d9d55f11SAurelien Jarno /* Store Clock */ 310d9d55f11SAurelien Jarno uint64_t HELPER(stck)(CPUS390XState *env) 311defb0e31SAlexander Graf { 312defb0e31SAlexander Graf uint64_t time; 313defb0e31SAlexander Graf 314defb0e31SAlexander Graf time = env->tod_offset + 315bc72ad67SAlex Bligh time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - env->tod_basetime); 316defb0e31SAlexander Graf 317defb0e31SAlexander Graf return time; 318defb0e31SAlexander Graf } 319defb0e31SAlexander Graf 320defb0e31SAlexander Graf /* Set Clock Comparator */ 321dd3eb7b5SRichard Henderson void HELPER(sckc)(CPUS390XState *env, uint64_t time) 322defb0e31SAlexander Graf { 323defb0e31SAlexander Graf if (time == -1ULL) { 324defb0e31SAlexander Graf return; 325defb0e31SAlexander Graf } 326defb0e31SAlexander Graf 327aa9e14e6SAurelien Jarno env->ckc = time; 328aa9e14e6SAurelien Jarno 329c941f074SAurelien Jarno /* difference between origins */ 330c941f074SAurelien Jarno time -= env->tod_offset; 331c941f074SAurelien Jarno 332defb0e31SAlexander Graf /* nanoseconds */ 3339cb32c44SAurelien Jarno time = tod2time(time); 334defb0e31SAlexander Graf 335c941f074SAurelien Jarno timer_mod(env->tod_timer, env->tod_basetime + time); 336defb0e31SAlexander Graf } 337defb0e31SAlexander Graf 338defb0e31SAlexander Graf /* Store Clock Comparator */ 339dd3eb7b5SRichard Henderson uint64_t HELPER(stckc)(CPUS390XState *env) 340defb0e31SAlexander Graf { 341aa9e14e6SAurelien Jarno return env->ckc; 342defb0e31SAlexander Graf } 343defb0e31SAlexander Graf 344defb0e31SAlexander Graf /* Set CPU Timer */ 345c4f0a863SRichard Henderson void HELPER(spt)(CPUS390XState *env, uint64_t time) 346defb0e31SAlexander Graf { 347defb0e31SAlexander Graf if (time == -1ULL) { 348defb0e31SAlexander Graf return; 349defb0e31SAlexander Graf } 350defb0e31SAlexander Graf 351defb0e31SAlexander Graf /* nanoseconds */ 3529cb32c44SAurelien Jarno time = tod2time(time); 353defb0e31SAlexander Graf 354b8ae94bdSAurelien Jarno env->cputm = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time; 355b8ae94bdSAurelien Jarno 356b8ae94bdSAurelien Jarno timer_mod(env->cpu_timer, env->cputm); 357defb0e31SAlexander Graf } 358defb0e31SAlexander Graf 359defb0e31SAlexander Graf /* Store CPU Timer */ 360c4f0a863SRichard Henderson uint64_t HELPER(stpt)(CPUS390XState *env) 361defb0e31SAlexander Graf { 362b8ae94bdSAurelien Jarno return time2tod(env->cputm - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); 363defb0e31SAlexander Graf } 364defb0e31SAlexander Graf 365defb0e31SAlexander Graf /* Store System Information */ 366d14b3e09SRichard Henderson uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, 367d14b3e09SRichard Henderson uint64_t r0, uint64_t r1) 368defb0e31SAlexander Graf { 369defb0e31SAlexander Graf int cc = 0; 370defb0e31SAlexander Graf int sel1, sel2; 371defb0e31SAlexander Graf 372defb0e31SAlexander Graf if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 && 373defb0e31SAlexander Graf ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) { 374defb0e31SAlexander Graf /* valid function code, invalid reserved bits */ 375defb0e31SAlexander Graf program_interrupt(env, PGM_SPECIFICATION, 2); 376defb0e31SAlexander Graf } 377defb0e31SAlexander Graf 378defb0e31SAlexander Graf sel1 = r0 & STSI_R0_SEL1_MASK; 379defb0e31SAlexander Graf sel2 = r1 & STSI_R1_SEL2_MASK; 380defb0e31SAlexander Graf 381defb0e31SAlexander Graf /* XXX: spec exception if sysib is not 4k-aligned */ 382defb0e31SAlexander Graf 383defb0e31SAlexander Graf switch (r0 & STSI_LEVEL_MASK) { 384defb0e31SAlexander Graf case STSI_LEVEL_1: 385defb0e31SAlexander Graf if ((sel1 == 1) && (sel2 == 1)) { 386defb0e31SAlexander Graf /* Basic Machine Configuration */ 387defb0e31SAlexander Graf struct sysib_111 sysib; 388defb0e31SAlexander Graf 389defb0e31SAlexander Graf memset(&sysib, 0, sizeof(sysib)); 390defb0e31SAlexander Graf ebcdic_put(sysib.manuf, "QEMU ", 16); 391defb0e31SAlexander Graf /* same as machine type number in STORE CPU ID */ 392defb0e31SAlexander Graf ebcdic_put(sysib.type, "QEMU", 4); 393defb0e31SAlexander Graf /* same as model number in STORE CPU ID */ 394defb0e31SAlexander Graf ebcdic_put(sysib.model, "QEMU ", 16); 395defb0e31SAlexander Graf ebcdic_put(sysib.sequence, "QEMU ", 16); 396defb0e31SAlexander Graf ebcdic_put(sysib.plant, "QEMU", 4); 397eb6282f2SStefan Weil cpu_physical_memory_write(a0, &sysib, sizeof(sysib)); 398defb0e31SAlexander Graf } else if ((sel1 == 2) && (sel2 == 1)) { 399defb0e31SAlexander Graf /* Basic Machine CPU */ 400defb0e31SAlexander Graf struct sysib_121 sysib; 401defb0e31SAlexander Graf 402defb0e31SAlexander Graf memset(&sysib, 0, sizeof(sysib)); 403defb0e31SAlexander Graf /* XXX make different for different CPUs? */ 404defb0e31SAlexander Graf ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16); 405defb0e31SAlexander Graf ebcdic_put(sysib.plant, "QEMU", 4); 406defb0e31SAlexander Graf stw_p(&sysib.cpu_addr, env->cpu_num); 407eb6282f2SStefan Weil cpu_physical_memory_write(a0, &sysib, sizeof(sysib)); 408defb0e31SAlexander Graf } else if ((sel1 == 2) && (sel2 == 2)) { 409defb0e31SAlexander Graf /* Basic Machine CPUs */ 410defb0e31SAlexander Graf struct sysib_122 sysib; 411defb0e31SAlexander Graf 412defb0e31SAlexander Graf memset(&sysib, 0, sizeof(sysib)); 413defb0e31SAlexander Graf stl_p(&sysib.capability, 0x443afc29); 414defb0e31SAlexander Graf /* XXX change when SMP comes */ 415defb0e31SAlexander Graf stw_p(&sysib.total_cpus, 1); 416defb0e31SAlexander Graf stw_p(&sysib.active_cpus, 1); 417defb0e31SAlexander Graf stw_p(&sysib.standby_cpus, 0); 418defb0e31SAlexander Graf stw_p(&sysib.reserved_cpus, 0); 419eb6282f2SStefan Weil cpu_physical_memory_write(a0, &sysib, sizeof(sysib)); 420defb0e31SAlexander Graf } else { 421defb0e31SAlexander Graf cc = 3; 422defb0e31SAlexander Graf } 423defb0e31SAlexander Graf break; 424defb0e31SAlexander Graf case STSI_LEVEL_2: 425defb0e31SAlexander Graf { 426defb0e31SAlexander Graf if ((sel1 == 2) && (sel2 == 1)) { 427defb0e31SAlexander Graf /* LPAR CPU */ 428defb0e31SAlexander Graf struct sysib_221 sysib; 429defb0e31SAlexander Graf 430defb0e31SAlexander Graf memset(&sysib, 0, sizeof(sysib)); 431defb0e31SAlexander Graf /* XXX make different for different CPUs? */ 432defb0e31SAlexander Graf ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16); 433defb0e31SAlexander Graf ebcdic_put(sysib.plant, "QEMU", 4); 434defb0e31SAlexander Graf stw_p(&sysib.cpu_addr, env->cpu_num); 435defb0e31SAlexander Graf stw_p(&sysib.cpu_id, 0); 436eb6282f2SStefan Weil cpu_physical_memory_write(a0, &sysib, sizeof(sysib)); 437defb0e31SAlexander Graf } else if ((sel1 == 2) && (sel2 == 2)) { 438defb0e31SAlexander Graf /* LPAR CPUs */ 439defb0e31SAlexander Graf struct sysib_222 sysib; 440defb0e31SAlexander Graf 441defb0e31SAlexander Graf memset(&sysib, 0, sizeof(sysib)); 442defb0e31SAlexander Graf stw_p(&sysib.lpar_num, 0); 443defb0e31SAlexander Graf sysib.lcpuc = 0; 444defb0e31SAlexander Graf /* XXX change when SMP comes */ 445defb0e31SAlexander Graf stw_p(&sysib.total_cpus, 1); 446defb0e31SAlexander Graf stw_p(&sysib.conf_cpus, 1); 447defb0e31SAlexander Graf stw_p(&sysib.standby_cpus, 0); 448defb0e31SAlexander Graf stw_p(&sysib.reserved_cpus, 0); 449defb0e31SAlexander Graf ebcdic_put(sysib.name, "QEMU ", 8); 450defb0e31SAlexander Graf stl_p(&sysib.caf, 1000); 451defb0e31SAlexander Graf stw_p(&sysib.dedicated_cpus, 0); 452defb0e31SAlexander Graf stw_p(&sysib.shared_cpus, 0); 453eb6282f2SStefan Weil cpu_physical_memory_write(a0, &sysib, sizeof(sysib)); 454defb0e31SAlexander Graf } else { 455defb0e31SAlexander Graf cc = 3; 456defb0e31SAlexander Graf } 457defb0e31SAlexander Graf break; 458defb0e31SAlexander Graf } 459defb0e31SAlexander Graf case STSI_LEVEL_3: 460defb0e31SAlexander Graf { 461defb0e31SAlexander Graf if ((sel1 == 2) && (sel2 == 2)) { 462defb0e31SAlexander Graf /* VM CPUs */ 463defb0e31SAlexander Graf struct sysib_322 sysib; 464defb0e31SAlexander Graf 465defb0e31SAlexander Graf memset(&sysib, 0, sizeof(sysib)); 466defb0e31SAlexander Graf sysib.count = 1; 467defb0e31SAlexander Graf /* XXX change when SMP comes */ 468defb0e31SAlexander Graf stw_p(&sysib.vm[0].total_cpus, 1); 469defb0e31SAlexander Graf stw_p(&sysib.vm[0].conf_cpus, 1); 470defb0e31SAlexander Graf stw_p(&sysib.vm[0].standby_cpus, 0); 471defb0e31SAlexander Graf stw_p(&sysib.vm[0].reserved_cpus, 0); 472defb0e31SAlexander Graf ebcdic_put(sysib.vm[0].name, "KVMguest", 8); 473defb0e31SAlexander Graf stl_p(&sysib.vm[0].caf, 1000); 474defb0e31SAlexander Graf ebcdic_put(sysib.vm[0].cpi, "KVM/Linux ", 16); 475eb6282f2SStefan Weil cpu_physical_memory_write(a0, &sysib, sizeof(sysib)); 476defb0e31SAlexander Graf } else { 477defb0e31SAlexander Graf cc = 3; 478defb0e31SAlexander Graf } 479defb0e31SAlexander Graf break; 480defb0e31SAlexander Graf } 481defb0e31SAlexander Graf case STSI_LEVEL_CURRENT: 482defb0e31SAlexander Graf env->regs[0] = STSI_LEVEL_3; 483defb0e31SAlexander Graf break; 484defb0e31SAlexander Graf default: 485defb0e31SAlexander Graf cc = 3; 486defb0e31SAlexander Graf break; 487defb0e31SAlexander Graf } 488defb0e31SAlexander Graf 489defb0e31SAlexander Graf return cc; 490defb0e31SAlexander Graf } 491defb0e31SAlexander Graf 492089f5c06SBlue Swirl uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1, 493089f5c06SBlue Swirl uint64_t cpu_addr) 494defb0e31SAlexander Graf { 4955172b780SDavid Hildenbrand int cc = SIGP_CC_ORDER_CODE_ACCEPTED; 496defb0e31SAlexander Graf 497defb0e31SAlexander Graf HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n", 49871e47088SBlue Swirl __func__, order_code, r1, cpu_addr); 499defb0e31SAlexander Graf 500defb0e31SAlexander Graf /* Remember: Use "R1 or R1 + 1, whichever is the odd-numbered register" 501defb0e31SAlexander Graf as parameter (input). Status (output) is always R1. */ 502defb0e31SAlexander Graf 503defb0e31SAlexander Graf switch (order_code) { 504defb0e31SAlexander Graf case SIGP_SET_ARCH: 505defb0e31SAlexander Graf /* switch arch */ 506defb0e31SAlexander Graf break; 507defb0e31SAlexander Graf case SIGP_SENSE: 508defb0e31SAlexander Graf /* enumerate CPU status */ 509defb0e31SAlexander Graf if (cpu_addr) { 510defb0e31SAlexander Graf /* XXX implement when SMP comes */ 511defb0e31SAlexander Graf return 3; 512defb0e31SAlexander Graf } 513defb0e31SAlexander Graf env->regs[r1] &= 0xffffffff00000000ULL; 514defb0e31SAlexander Graf cc = 1; 515defb0e31SAlexander Graf break; 5161864b94aSAlexander Graf #if !defined(CONFIG_USER_ONLY) 5171864b94aSAlexander Graf case SIGP_RESTART: 5181864b94aSAlexander Graf qemu_system_reset_request(); 5195638d180SAndreas Färber cpu_loop_exit(CPU(s390_env_get_cpu(env))); 5201864b94aSAlexander Graf break; 5211864b94aSAlexander Graf case SIGP_STOP: 5221864b94aSAlexander Graf qemu_system_shutdown_request(); 5235638d180SAndreas Färber cpu_loop_exit(CPU(s390_env_get_cpu(env))); 5241864b94aSAlexander Graf break; 5251864b94aSAlexander Graf #endif 526defb0e31SAlexander Graf default: 527defb0e31SAlexander Graf /* unknown sigp */ 528defb0e31SAlexander Graf fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code); 5295172b780SDavid Hildenbrand cc = SIGP_CC_NOT_OPERATIONAL; 530defb0e31SAlexander Graf } 531defb0e31SAlexander Graf 532defb0e31SAlexander Graf return cc; 533defb0e31SAlexander Graf } 534defb0e31SAlexander Graf #endif 535ad8a4570SAlexander Graf 536ad8a4570SAlexander Graf #ifndef CONFIG_USER_ONLY 537ad8a4570SAlexander Graf void HELPER(xsch)(CPUS390XState *env, uint64_t r1) 538ad8a4570SAlexander Graf { 539ad8a4570SAlexander Graf S390CPU *cpu = s390_env_get_cpu(env); 540ad8a4570SAlexander Graf ioinst_handle_xsch(cpu, r1); 541ad8a4570SAlexander Graf } 542ad8a4570SAlexander Graf 543ad8a4570SAlexander Graf void HELPER(csch)(CPUS390XState *env, uint64_t r1) 544ad8a4570SAlexander Graf { 545ad8a4570SAlexander Graf S390CPU *cpu = s390_env_get_cpu(env); 546ad8a4570SAlexander Graf ioinst_handle_csch(cpu, r1); 547ad8a4570SAlexander Graf } 548ad8a4570SAlexander Graf 549ad8a4570SAlexander Graf void HELPER(hsch)(CPUS390XState *env, uint64_t r1) 550ad8a4570SAlexander Graf { 551ad8a4570SAlexander Graf S390CPU *cpu = s390_env_get_cpu(env); 552ad8a4570SAlexander Graf ioinst_handle_hsch(cpu, r1); 553ad8a4570SAlexander Graf } 554ad8a4570SAlexander Graf 555ad8a4570SAlexander Graf void HELPER(msch)(CPUS390XState *env, uint64_t r1, uint64_t inst) 556ad8a4570SAlexander Graf { 557ad8a4570SAlexander Graf S390CPU *cpu = s390_env_get_cpu(env); 558ad8a4570SAlexander Graf ioinst_handle_msch(cpu, r1, inst >> 16); 559ad8a4570SAlexander Graf } 560ad8a4570SAlexander Graf 561ad8a4570SAlexander Graf void HELPER(rchp)(CPUS390XState *env, uint64_t r1) 562ad8a4570SAlexander Graf { 563ad8a4570SAlexander Graf S390CPU *cpu = s390_env_get_cpu(env); 564ad8a4570SAlexander Graf ioinst_handle_rchp(cpu, r1); 565ad8a4570SAlexander Graf } 566ad8a4570SAlexander Graf 567ad8a4570SAlexander Graf void HELPER(rsch)(CPUS390XState *env, uint64_t r1) 568ad8a4570SAlexander Graf { 569ad8a4570SAlexander Graf S390CPU *cpu = s390_env_get_cpu(env); 570ad8a4570SAlexander Graf ioinst_handle_rsch(cpu, r1); 571ad8a4570SAlexander Graf } 572ad8a4570SAlexander Graf 573ad8a4570SAlexander Graf void HELPER(ssch)(CPUS390XState *env, uint64_t r1, uint64_t inst) 574ad8a4570SAlexander Graf { 575ad8a4570SAlexander Graf S390CPU *cpu = s390_env_get_cpu(env); 576ad8a4570SAlexander Graf ioinst_handle_ssch(cpu, r1, inst >> 16); 577ad8a4570SAlexander Graf } 578ad8a4570SAlexander Graf 579ad8a4570SAlexander Graf void HELPER(stsch)(CPUS390XState *env, uint64_t r1, uint64_t inst) 580ad8a4570SAlexander Graf { 581ad8a4570SAlexander Graf S390CPU *cpu = s390_env_get_cpu(env); 582ad8a4570SAlexander Graf ioinst_handle_stsch(cpu, r1, inst >> 16); 583ad8a4570SAlexander Graf } 584ad8a4570SAlexander Graf 585ad8a4570SAlexander Graf void HELPER(tsch)(CPUS390XState *env, uint64_t r1, uint64_t inst) 586ad8a4570SAlexander Graf { 587ad8a4570SAlexander Graf S390CPU *cpu = s390_env_get_cpu(env); 588ad8a4570SAlexander Graf ioinst_handle_tsch(cpu, r1, inst >> 16); 589ad8a4570SAlexander Graf } 590ad8a4570SAlexander Graf 591ad8a4570SAlexander Graf void HELPER(chsc)(CPUS390XState *env, uint64_t inst) 592ad8a4570SAlexander Graf { 593ad8a4570SAlexander Graf S390CPU *cpu = s390_env_get_cpu(env); 594ad8a4570SAlexander Graf ioinst_handle_chsc(cpu, inst >> 16); 595ad8a4570SAlexander Graf } 596ad8a4570SAlexander Graf #endif 597777c98c3SAurelien Jarno 598777c98c3SAurelien Jarno #ifndef CONFIG_USER_ONLY 599777c98c3SAurelien Jarno void HELPER(per_check_exception)(CPUS390XState *env) 600777c98c3SAurelien Jarno { 601777c98c3SAurelien Jarno CPUState *cs = CPU(s390_env_get_cpu(env)); 602777c98c3SAurelien Jarno 603777c98c3SAurelien Jarno if (env->per_perc_atmid) { 604777c98c3SAurelien Jarno env->int_pgm_code = PGM_PER; 605777c98c3SAurelien Jarno env->int_pgm_ilen = get_ilen(cpu_ldub_code(env, env->per_address)); 606777c98c3SAurelien Jarno 607777c98c3SAurelien Jarno cs->exception_index = EXCP_PGM; 608777c98c3SAurelien Jarno cpu_loop_exit(cs); 609777c98c3SAurelien Jarno } 610777c98c3SAurelien Jarno } 611777c98c3SAurelien Jarno #endif 612