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 219615495aSPeter Maydell #include "qemu/osdep.h" 22*278f5e98SAlex Bennée #include "qemu/main-loop.h" 233e457172SBlue Swirl #include "cpu.h" 24022c62cbSPaolo Bonzini #include "exec/memory.h" 251de7afc9SPaolo Bonzini #include "qemu/host-utils.h" 262ef6175aSRichard Henderson #include "exec/helper-proto.h" 279c17d615SPaolo Bonzini #include "sysemu/kvm.h" 281de7afc9SPaolo Bonzini #include "qemu/timer.h" 298d04fb55SJan Kiszka #include "qemu/main-loop.h" 30df75a4e2SFan Zhang #include "exec/address-spaces.h" 31af2be207SJan Kiszka #ifdef CONFIG_KVM 32af2be207SJan Kiszka #include <linux/kvm.h> 33af2be207SJan Kiszka #endif 3463c91552SPaolo Bonzini #include "exec/exec-all.h" 35f08b6170SPaolo Bonzini #include "exec/cpu_ldst.h" 3610ec5117SAlexander Graf 371864b94aSAlexander Graf #if !defined(CONFIG_USER_ONLY) 38741da0d3SPaolo Bonzini #include "hw/watchdog/wdt_diag288.h" 39f0778475SChristian Borntraeger #include "sysemu/cpus.h" 409c17d615SPaolo Bonzini #include "sysemu/sysemu.h" 4140fa5264SHeinz Graalfs #include "hw/s390x/ebcdic.h" 42df75a4e2SFan Zhang #include "hw/s390x/ipl.h" 4310ec5117SAlexander Graf #endif 44d5a43964SAlexander Graf 45defb0e31SAlexander Graf /* #define DEBUG_HELPER */ 46defb0e31SAlexander Graf #ifdef DEBUG_HELPER 47defb0e31SAlexander Graf #define HELPER_LOG(x...) qemu_log(x) 48defb0e31SAlexander Graf #else 49defb0e31SAlexander Graf #define HELPER_LOG(x...) 50defb0e31SAlexander Graf #endif 51defb0e31SAlexander Graf 52b4e2bd35SRichard Henderson /* Raise an exception dynamically from a helper function. */ 53b4e2bd35SRichard Henderson void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp, 54b4e2bd35SRichard Henderson uintptr_t retaddr) 55b4e2bd35SRichard Henderson { 5627103424SAndreas Färber CPUState *cs = CPU(s390_env_get_cpu(env)); 57b4e2bd35SRichard Henderson int t; 58b4e2bd35SRichard Henderson 5927103424SAndreas Färber cs->exception_index = EXCP_PGM; 60b4e2bd35SRichard Henderson env->int_pgm_code = excp; 61b4e2bd35SRichard Henderson 62b4e2bd35SRichard Henderson /* Use the (ultimate) callers address to find the insn that trapped. */ 633f38f309SAndreas Färber cpu_restore_state(cs, retaddr); 64b4e2bd35SRichard Henderson 65b4e2bd35SRichard Henderson /* Advance past the insn. */ 66b4e2bd35SRichard Henderson t = cpu_ldub_code(env, env->psw.addr); 67b4e2bd35SRichard Henderson env->int_pgm_ilen = t = get_ilen(t); 689bebf986SAurelien Jarno env->psw.addr += t; 69b4e2bd35SRichard Henderson 705638d180SAndreas Färber cpu_loop_exit(cs); 71b4e2bd35SRichard Henderson } 72b4e2bd35SRichard Henderson 73d5a103cdSRichard Henderson /* Raise an exception statically from a TB. */ 74089f5c06SBlue Swirl void HELPER(exception)(CPUS390XState *env, uint32_t excp) 75defb0e31SAlexander Graf { 7627103424SAndreas Färber CPUState *cs = CPU(s390_env_get_cpu(env)); 7727103424SAndreas Färber 7871e47088SBlue Swirl HELPER_LOG("%s: exception %d\n", __func__, excp); 7927103424SAndreas Färber cs->exception_index = excp; 805638d180SAndreas Färber cpu_loop_exit(cs); 81defb0e31SAlexander Graf } 82defb0e31SAlexander Graf 83defb0e31SAlexander Graf #ifndef CONFIG_USER_ONLY 84a158986dSStefan Weil 85d5a103cdSRichard Henderson void program_interrupt(CPUS390XState *env, uint32_t code, int ilen) 86defb0e31SAlexander Graf { 8727103424SAndreas Färber S390CPU *cpu = s390_env_get_cpu(env); 8827103424SAndreas Färber 890d404541SRichard Henderson qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n", 900d404541SRichard Henderson env->psw.addr); 91defb0e31SAlexander Graf 92defb0e31SAlexander Graf if (kvm_enabled()) { 93af2be207SJan Kiszka #ifdef CONFIG_KVM 94de13d216SCornelia Huck struct kvm_s390_irq irq = { 95de13d216SCornelia Huck .type = KVM_S390_PROGRAM_INT, 96de13d216SCornelia Huck .u.pgm.code = code, 97de13d216SCornelia Huck }; 98de13d216SCornelia Huck 99de13d216SCornelia Huck kvm_s390_vcpu_interrupt(cpu, &irq); 100af2be207SJan Kiszka #endif 101defb0e31SAlexander Graf } else { 10227103424SAndreas Färber CPUState *cs = CPU(cpu); 10327103424SAndreas Färber 104defb0e31SAlexander Graf env->int_pgm_code = code; 105d5a103cdSRichard Henderson env->int_pgm_ilen = ilen; 10627103424SAndreas Färber cs->exception_index = EXCP_PGM; 1075638d180SAndreas Färber cpu_loop_exit(cs); 108defb0e31SAlexander Graf } 109defb0e31SAlexander Graf } 110defb0e31SAlexander Graf 111defb0e31SAlexander Graf /* SCLP service call */ 112dc458df9SRichard Henderson uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2) 113defb0e31SAlexander Graf { 1148d04fb55SJan Kiszka qemu_mutex_lock_iothread(); 1156e252802SThomas Huth int r = sclp_service_call(env, r1, r2); 1169abf567dSChristian Borntraeger if (r < 0) { 1179abf567dSChristian Borntraeger program_interrupt(env, -r, 4); 1188d04fb55SJan Kiszka r = 0; 119d5a43964SAlexander Graf } 1208d04fb55SJan Kiszka qemu_mutex_unlock_iothread(); 1219abf567dSChristian Borntraeger return r; 1229abf567dSChristian Borntraeger } 123defb0e31SAlexander Graf 124268846baSEugene (jno) Dvurechenski #ifndef CONFIG_USER_ONLY 125d8b30c83SChristian Borntraeger static int modified_clear_reset(S390CPU *cpu) 126d8b30c83SChristian Borntraeger { 127d8b30c83SChristian Borntraeger S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); 12885ca3371SDavid Hildenbrand CPUState *t; 129d8b30c83SChristian Borntraeger 130d8b30c83SChristian Borntraeger pause_all_vcpus(); 131d8b30c83SChristian Borntraeger cpu_synchronize_all_states(); 13285ca3371SDavid Hildenbrand CPU_FOREACH(t) { 13314e6fe12SPaolo Bonzini run_on_cpu(t, s390_do_cpu_full_reset, RUN_ON_CPU_NULL); 13485ca3371SDavid Hildenbrand } 1351cd4e0f6SDavid Hildenbrand s390_cmma_reset(); 136d9f090ecSDavid Hildenbrand subsystem_reset(); 1374ab72920SDavid Hildenbrand s390_crypto_reset(); 138d8b30c83SChristian Borntraeger scc->load_normal(CPU(cpu)); 139d8b30c83SChristian Borntraeger cpu_synchronize_all_post_reset(); 140d8b30c83SChristian Borntraeger resume_all_vcpus(); 141d8b30c83SChristian Borntraeger return 0; 142d8b30c83SChristian Borntraeger } 143d8b30c83SChristian Borntraeger 144f0778475SChristian Borntraeger static int load_normal_reset(S390CPU *cpu) 145f0778475SChristian Borntraeger { 146f0778475SChristian Borntraeger S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); 14785ca3371SDavid Hildenbrand CPUState *t; 148f0778475SChristian Borntraeger 149f0778475SChristian Borntraeger pause_all_vcpus(); 150f0778475SChristian Borntraeger cpu_synchronize_all_states(); 15185ca3371SDavid Hildenbrand CPU_FOREACH(t) { 15214e6fe12SPaolo Bonzini run_on_cpu(t, s390_do_cpu_reset, RUN_ON_CPU_NULL); 15385ca3371SDavid Hildenbrand } 1541cd4e0f6SDavid Hildenbrand s390_cmma_reset(); 155d9f090ecSDavid Hildenbrand subsystem_reset(); 156f0778475SChristian Borntraeger scc->initial_cpu_reset(CPU(cpu)); 157f0778475SChristian Borntraeger scc->load_normal(CPU(cpu)); 158f0778475SChristian Borntraeger cpu_synchronize_all_post_reset(); 159f0778475SChristian Borntraeger resume_all_vcpus(); 160f0778475SChristian Borntraeger return 0; 161f0778475SChristian Borntraeger } 162f0778475SChristian Borntraeger 1638fc639afSXu Wang int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3) 1648fc639afSXu Wang { 1658fc639afSXu Wang uint64_t func = env->regs[r1]; 1668fc639afSXu Wang uint64_t timeout = env->regs[r1 + 1]; 1678fc639afSXu Wang uint64_t action = env->regs[r3]; 1688fc639afSXu Wang Object *obj; 1698fc639afSXu Wang DIAG288State *diag288; 1708fc639afSXu Wang DIAG288Class *diag288_class; 1718fc639afSXu Wang 1728fc639afSXu Wang if (r1 % 2 || action != 0) { 1738fc639afSXu Wang return -1; 1748fc639afSXu Wang } 1758fc639afSXu Wang 1768fc639afSXu Wang /* Timeout must be more than 15 seconds except for timer deletion */ 1778fc639afSXu Wang if (func != WDT_DIAG288_CANCEL && timeout < 15) { 1788fc639afSXu Wang return -1; 1798fc639afSXu Wang } 1808fc639afSXu Wang 1818fc639afSXu Wang obj = object_resolve_path_type("", TYPE_WDT_DIAG288, NULL); 1828fc639afSXu Wang if (!obj) { 1838fc639afSXu Wang return -1; 1848fc639afSXu Wang } 1858fc639afSXu Wang 1868fc639afSXu Wang diag288 = DIAG288(obj); 1878fc639afSXu Wang diag288_class = DIAG288_GET_CLASS(diag288); 1888fc639afSXu Wang return diag288_class->handle_timer(diag288, func, timeout); 1898fc639afSXu Wang } 1908fc639afSXu Wang 191df75a4e2SFan Zhang #define DIAG_308_RC_OK 0x0001 192268846baSEugene (jno) Dvurechenski #define DIAG_308_RC_NO_CONF 0x0102 193268846baSEugene (jno) Dvurechenski #define DIAG_308_RC_INVALID 0x0402 194df75a4e2SFan Zhang 195268846baSEugene (jno) Dvurechenski void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3) 196268846baSEugene (jno) Dvurechenski { 197268846baSEugene (jno) Dvurechenski uint64_t addr = env->regs[r1]; 198268846baSEugene (jno) Dvurechenski uint64_t subcode = env->regs[r3]; 199df75a4e2SFan Zhang IplParameterBlock *iplb; 200268846baSEugene (jno) Dvurechenski 201268846baSEugene (jno) Dvurechenski if (env->psw.mask & PSW_MASK_PSTATE) { 202268846baSEugene (jno) Dvurechenski program_interrupt(env, PGM_PRIVILEGED, ILEN_LATER_INC); 203268846baSEugene (jno) Dvurechenski return; 204268846baSEugene (jno) Dvurechenski } 205268846baSEugene (jno) Dvurechenski 206268846baSEugene (jno) Dvurechenski if ((subcode & ~0x0ffffULL) || (subcode > 6)) { 207268846baSEugene (jno) Dvurechenski program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC); 208268846baSEugene (jno) Dvurechenski return; 209268846baSEugene (jno) Dvurechenski } 210268846baSEugene (jno) Dvurechenski 211268846baSEugene (jno) Dvurechenski switch (subcode) { 212d8b30c83SChristian Borntraeger case 0: 213d8b30c83SChristian Borntraeger modified_clear_reset(s390_env_get_cpu(env)); 2148df7eef3SAurelien Jarno if (tcg_enabled()) { 2158df7eef3SAurelien Jarno cpu_loop_exit(CPU(s390_env_get_cpu(env))); 2168df7eef3SAurelien Jarno } 217d8b30c83SChristian Borntraeger break; 218f0778475SChristian Borntraeger case 1: 219f0778475SChristian Borntraeger load_normal_reset(s390_env_get_cpu(env)); 2208df7eef3SAurelien Jarno if (tcg_enabled()) { 2218df7eef3SAurelien Jarno cpu_loop_exit(CPU(s390_env_get_cpu(env))); 2228df7eef3SAurelien Jarno } 223f0778475SChristian Borntraeger break; 2242ecacb0bSAurelien Jarno case 3: 2252ecacb0bSAurelien Jarno s390_reipl_request(); 2262ecacb0bSAurelien Jarno if (tcg_enabled()) { 2272ecacb0bSAurelien Jarno cpu_loop_exit(CPU(s390_env_get_cpu(env))); 2282ecacb0bSAurelien Jarno } 2292ecacb0bSAurelien Jarno break; 230268846baSEugene (jno) Dvurechenski case 5: 231268846baSEugene (jno) Dvurechenski if ((r1 & 1) || (addr & 0x0fffULL)) { 232268846baSEugene (jno) Dvurechenski program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC); 233268846baSEugene (jno) Dvurechenski return; 234268846baSEugene (jno) Dvurechenski } 235df75a4e2SFan Zhang if (!address_space_access_valid(&address_space_memory, addr, 236df75a4e2SFan Zhang sizeof(IplParameterBlock), false)) { 237df75a4e2SFan Zhang program_interrupt(env, PGM_ADDRESSING, ILEN_LATER_INC); 238df75a4e2SFan Zhang return; 239df75a4e2SFan Zhang } 24004ca4b92SAlexander Yarygin iplb = g_malloc0(sizeof(IplParameterBlock)); 2419946a911SAlexander Yarygin cpu_physical_memory_read(addr, iplb, sizeof(iplb->len)); 2429946a911SAlexander Yarygin if (!iplb_valid_len(iplb)) { 2439946a911SAlexander Yarygin env->regs[r1 + 1] = DIAG_308_RC_INVALID; 2449946a911SAlexander Yarygin goto out; 2459946a911SAlexander Yarygin } 2469946a911SAlexander Yarygin 2479946a911SAlexander Yarygin cpu_physical_memory_read(addr, iplb, be32_to_cpu(iplb->len)); 2489946a911SAlexander Yarygin 2499946a911SAlexander Yarygin if (!iplb_valid_ccw(iplb) && !iplb_valid_fcp(iplb)) { 2509946a911SAlexander Yarygin env->regs[r1 + 1] = DIAG_308_RC_INVALID; 2519946a911SAlexander Yarygin goto out; 2529946a911SAlexander Yarygin } 2539946a911SAlexander Yarygin 254feacc6c2SDavid Hildenbrand s390_ipl_update_diag308(iplb); 255df75a4e2SFan Zhang env->regs[r1 + 1] = DIAG_308_RC_OK; 2569946a911SAlexander Yarygin out: 257df75a4e2SFan Zhang g_free(iplb); 258268846baSEugene (jno) Dvurechenski return; 259268846baSEugene (jno) Dvurechenski case 6: 260268846baSEugene (jno) Dvurechenski if ((r1 & 1) || (addr & 0x0fffULL)) { 261268846baSEugene (jno) Dvurechenski program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC); 262268846baSEugene (jno) Dvurechenski return; 263268846baSEugene (jno) Dvurechenski } 264df75a4e2SFan Zhang if (!address_space_access_valid(&address_space_memory, addr, 265df75a4e2SFan Zhang sizeof(IplParameterBlock), true)) { 266df75a4e2SFan Zhang program_interrupt(env, PGM_ADDRESSING, ILEN_LATER_INC); 267df75a4e2SFan Zhang return; 268df75a4e2SFan Zhang } 269df75a4e2SFan Zhang iplb = s390_ipl_get_iplb(); 270df75a4e2SFan Zhang if (iplb) { 2719946a911SAlexander Yarygin cpu_physical_memory_write(addr, iplb, be32_to_cpu(iplb->len)); 272df75a4e2SFan Zhang env->regs[r1 + 1] = DIAG_308_RC_OK; 273df75a4e2SFan Zhang } else { 274268846baSEugene (jno) Dvurechenski env->regs[r1 + 1] = DIAG_308_RC_NO_CONF; 275df75a4e2SFan Zhang } 276268846baSEugene (jno) Dvurechenski return; 277268846baSEugene (jno) Dvurechenski default: 278268846baSEugene (jno) Dvurechenski hw_error("Unhandled diag308 subcode %" PRIx64, subcode); 279268846baSEugene (jno) Dvurechenski break; 280268846baSEugene (jno) Dvurechenski } 281268846baSEugene (jno) Dvurechenski } 282268846baSEugene (jno) Dvurechenski #endif 283268846baSEugene (jno) Dvurechenski 2848df7eef3SAurelien Jarno void HELPER(diag)(CPUS390XState *env, uint32_t r1, uint32_t r3, uint32_t num) 285defb0e31SAlexander Graf { 286defb0e31SAlexander Graf uint64_t r; 287defb0e31SAlexander Graf 288defb0e31SAlexander Graf switch (num) { 289defb0e31SAlexander Graf case 0x500: 290defb0e31SAlexander Graf /* KVM hypercall */ 29128e942f8SCornelia Huck r = s390_virtio_hypercall(env); 292defb0e31SAlexander Graf break; 293defb0e31SAlexander Graf case 0x44: 294defb0e31SAlexander Graf /* yield */ 295defb0e31SAlexander Graf r = 0; 296defb0e31SAlexander Graf break; 297defb0e31SAlexander Graf case 0x308: 298defb0e31SAlexander Graf /* ipl */ 2998df7eef3SAurelien Jarno handle_diag_308(env, r1, r3); 300defb0e31SAlexander Graf r = 0; 301defb0e31SAlexander Graf break; 302defb0e31SAlexander Graf default: 303defb0e31SAlexander Graf r = -1; 304defb0e31SAlexander Graf break; 305defb0e31SAlexander Graf } 306defb0e31SAlexander Graf 307defb0e31SAlexander Graf if (r) { 308d5a103cdSRichard Henderson program_interrupt(env, PGM_OPERATION, ILEN_LATER_INC); 309defb0e31SAlexander Graf } 310defb0e31SAlexander Graf } 311defb0e31SAlexander Graf 312defb0e31SAlexander Graf /* Set Prefix */ 313089f5c06SBlue Swirl void HELPER(spx)(CPUS390XState *env, uint64_t a1) 314defb0e31SAlexander Graf { 31531b030d4SAndreas Färber CPUState *cs = CPU(s390_env_get_cpu(env)); 316e805a0d3SRichard Henderson uint32_t prefix = a1 & 0x7fffe000; 31731b030d4SAndreas Färber 318e805a0d3SRichard Henderson env->psa = prefix; 319aafcf80eSPaolo Bonzini HELPER_LOG("prefix: %#x\n", prefix); 32031b030d4SAndreas Färber tlb_flush_page(cs, 0); 32131b030d4SAndreas Färber tlb_flush_page(cs, TARGET_PAGE_SIZE); 322defb0e31SAlexander Graf } 323defb0e31SAlexander Graf 324d9d55f11SAurelien Jarno /* Store Clock */ 325d9d55f11SAurelien Jarno uint64_t HELPER(stck)(CPUS390XState *env) 326defb0e31SAlexander Graf { 327defb0e31SAlexander Graf uint64_t time; 328defb0e31SAlexander Graf 329defb0e31SAlexander Graf time = env->tod_offset + 330bc72ad67SAlex Bligh time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - env->tod_basetime); 331defb0e31SAlexander Graf 332defb0e31SAlexander Graf return time; 333defb0e31SAlexander Graf } 334defb0e31SAlexander Graf 335defb0e31SAlexander Graf /* Set Clock Comparator */ 336dd3eb7b5SRichard Henderson void HELPER(sckc)(CPUS390XState *env, uint64_t time) 337defb0e31SAlexander Graf { 338defb0e31SAlexander Graf if (time == -1ULL) { 339defb0e31SAlexander Graf return; 340defb0e31SAlexander Graf } 341defb0e31SAlexander Graf 342aa9e14e6SAurelien Jarno env->ckc = time; 343aa9e14e6SAurelien Jarno 344c941f074SAurelien Jarno /* difference between origins */ 345c941f074SAurelien Jarno time -= env->tod_offset; 346c941f074SAurelien Jarno 347defb0e31SAlexander Graf /* nanoseconds */ 3489cb32c44SAurelien Jarno time = tod2time(time); 349defb0e31SAlexander Graf 350c941f074SAurelien Jarno timer_mod(env->tod_timer, env->tod_basetime + time); 351defb0e31SAlexander Graf } 352defb0e31SAlexander Graf 353defb0e31SAlexander Graf /* Store Clock Comparator */ 354dd3eb7b5SRichard Henderson uint64_t HELPER(stckc)(CPUS390XState *env) 355defb0e31SAlexander Graf { 356aa9e14e6SAurelien Jarno return env->ckc; 357defb0e31SAlexander Graf } 358defb0e31SAlexander Graf 359defb0e31SAlexander Graf /* Set CPU Timer */ 360c4f0a863SRichard Henderson void HELPER(spt)(CPUS390XState *env, uint64_t time) 361defb0e31SAlexander Graf { 362defb0e31SAlexander Graf if (time == -1ULL) { 363defb0e31SAlexander Graf return; 364defb0e31SAlexander Graf } 365defb0e31SAlexander Graf 366defb0e31SAlexander Graf /* nanoseconds */ 3679cb32c44SAurelien Jarno time = tod2time(time); 368defb0e31SAlexander Graf 369b8ae94bdSAurelien Jarno env->cputm = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time; 370b8ae94bdSAurelien Jarno 371b8ae94bdSAurelien Jarno timer_mod(env->cpu_timer, env->cputm); 372defb0e31SAlexander Graf } 373defb0e31SAlexander Graf 374defb0e31SAlexander Graf /* Store CPU Timer */ 375c4f0a863SRichard Henderson uint64_t HELPER(stpt)(CPUS390XState *env) 376defb0e31SAlexander Graf { 377b8ae94bdSAurelien Jarno return time2tod(env->cputm - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); 378defb0e31SAlexander Graf } 379defb0e31SAlexander Graf 380defb0e31SAlexander Graf /* Store System Information */ 381d14b3e09SRichard Henderson uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, 382d14b3e09SRichard Henderson uint64_t r0, uint64_t r1) 383defb0e31SAlexander Graf { 384defb0e31SAlexander Graf int cc = 0; 385defb0e31SAlexander Graf int sel1, sel2; 386defb0e31SAlexander Graf 387defb0e31SAlexander Graf if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 && 388defb0e31SAlexander Graf ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) { 389defb0e31SAlexander Graf /* valid function code, invalid reserved bits */ 390defb0e31SAlexander Graf program_interrupt(env, PGM_SPECIFICATION, 2); 391defb0e31SAlexander Graf } 392defb0e31SAlexander Graf 393defb0e31SAlexander Graf sel1 = r0 & STSI_R0_SEL1_MASK; 394defb0e31SAlexander Graf sel2 = r1 & STSI_R1_SEL2_MASK; 395defb0e31SAlexander Graf 396defb0e31SAlexander Graf /* XXX: spec exception if sysib is not 4k-aligned */ 397defb0e31SAlexander Graf 398defb0e31SAlexander Graf switch (r0 & STSI_LEVEL_MASK) { 399defb0e31SAlexander Graf case STSI_LEVEL_1: 400defb0e31SAlexander Graf if ((sel1 == 1) && (sel2 == 1)) { 401defb0e31SAlexander Graf /* Basic Machine Configuration */ 402defb0e31SAlexander Graf struct sysib_111 sysib; 403defb0e31SAlexander Graf 404defb0e31SAlexander Graf memset(&sysib, 0, sizeof(sysib)); 405defb0e31SAlexander Graf ebcdic_put(sysib.manuf, "QEMU ", 16); 406defb0e31SAlexander Graf /* same as machine type number in STORE CPU ID */ 407defb0e31SAlexander Graf ebcdic_put(sysib.type, "QEMU", 4); 408defb0e31SAlexander Graf /* same as model number in STORE CPU ID */ 409defb0e31SAlexander Graf ebcdic_put(sysib.model, "QEMU ", 16); 410defb0e31SAlexander Graf ebcdic_put(sysib.sequence, "QEMU ", 16); 411defb0e31SAlexander Graf ebcdic_put(sysib.plant, "QEMU", 4); 412eb6282f2SStefan Weil cpu_physical_memory_write(a0, &sysib, sizeof(sysib)); 413defb0e31SAlexander Graf } else if ((sel1 == 2) && (sel2 == 1)) { 414defb0e31SAlexander Graf /* Basic Machine CPU */ 415defb0e31SAlexander Graf struct sysib_121 sysib; 416defb0e31SAlexander Graf 417defb0e31SAlexander Graf memset(&sysib, 0, sizeof(sysib)); 418defb0e31SAlexander Graf /* XXX make different for different CPUs? */ 419defb0e31SAlexander Graf ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16); 420defb0e31SAlexander Graf ebcdic_put(sysib.plant, "QEMU", 4); 421defb0e31SAlexander Graf stw_p(&sysib.cpu_addr, env->cpu_num); 422eb6282f2SStefan Weil cpu_physical_memory_write(a0, &sysib, sizeof(sysib)); 423defb0e31SAlexander Graf } else if ((sel1 == 2) && (sel2 == 2)) { 424defb0e31SAlexander Graf /* Basic Machine CPUs */ 425defb0e31SAlexander Graf struct sysib_122 sysib; 426defb0e31SAlexander Graf 427defb0e31SAlexander Graf memset(&sysib, 0, sizeof(sysib)); 428defb0e31SAlexander Graf stl_p(&sysib.capability, 0x443afc29); 429defb0e31SAlexander Graf /* XXX change when SMP comes */ 430defb0e31SAlexander Graf stw_p(&sysib.total_cpus, 1); 431defb0e31SAlexander Graf stw_p(&sysib.active_cpus, 1); 432defb0e31SAlexander Graf stw_p(&sysib.standby_cpus, 0); 433defb0e31SAlexander Graf stw_p(&sysib.reserved_cpus, 0); 434eb6282f2SStefan Weil cpu_physical_memory_write(a0, &sysib, sizeof(sysib)); 435defb0e31SAlexander Graf } else { 436defb0e31SAlexander Graf cc = 3; 437defb0e31SAlexander Graf } 438defb0e31SAlexander Graf break; 439defb0e31SAlexander Graf case STSI_LEVEL_2: 440defb0e31SAlexander Graf { 441defb0e31SAlexander Graf if ((sel1 == 2) && (sel2 == 1)) { 442defb0e31SAlexander Graf /* LPAR CPU */ 443defb0e31SAlexander Graf struct sysib_221 sysib; 444defb0e31SAlexander Graf 445defb0e31SAlexander Graf memset(&sysib, 0, sizeof(sysib)); 446defb0e31SAlexander Graf /* XXX make different for different CPUs? */ 447defb0e31SAlexander Graf ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16); 448defb0e31SAlexander Graf ebcdic_put(sysib.plant, "QEMU", 4); 449defb0e31SAlexander Graf stw_p(&sysib.cpu_addr, env->cpu_num); 450defb0e31SAlexander Graf stw_p(&sysib.cpu_id, 0); 451eb6282f2SStefan Weil cpu_physical_memory_write(a0, &sysib, sizeof(sysib)); 452defb0e31SAlexander Graf } else if ((sel1 == 2) && (sel2 == 2)) { 453defb0e31SAlexander Graf /* LPAR CPUs */ 454defb0e31SAlexander Graf struct sysib_222 sysib; 455defb0e31SAlexander Graf 456defb0e31SAlexander Graf memset(&sysib, 0, sizeof(sysib)); 457defb0e31SAlexander Graf stw_p(&sysib.lpar_num, 0); 458defb0e31SAlexander Graf sysib.lcpuc = 0; 459defb0e31SAlexander Graf /* XXX change when SMP comes */ 460defb0e31SAlexander Graf stw_p(&sysib.total_cpus, 1); 461defb0e31SAlexander Graf stw_p(&sysib.conf_cpus, 1); 462defb0e31SAlexander Graf stw_p(&sysib.standby_cpus, 0); 463defb0e31SAlexander Graf stw_p(&sysib.reserved_cpus, 0); 464defb0e31SAlexander Graf ebcdic_put(sysib.name, "QEMU ", 8); 465defb0e31SAlexander Graf stl_p(&sysib.caf, 1000); 466defb0e31SAlexander Graf stw_p(&sysib.dedicated_cpus, 0); 467defb0e31SAlexander Graf stw_p(&sysib.shared_cpus, 0); 468eb6282f2SStefan Weil cpu_physical_memory_write(a0, &sysib, sizeof(sysib)); 469defb0e31SAlexander Graf } else { 470defb0e31SAlexander Graf cc = 3; 471defb0e31SAlexander Graf } 472defb0e31SAlexander Graf break; 473defb0e31SAlexander Graf } 474defb0e31SAlexander Graf case STSI_LEVEL_3: 475defb0e31SAlexander Graf { 476defb0e31SAlexander Graf if ((sel1 == 2) && (sel2 == 2)) { 477defb0e31SAlexander Graf /* VM CPUs */ 478defb0e31SAlexander Graf struct sysib_322 sysib; 479defb0e31SAlexander Graf 480defb0e31SAlexander Graf memset(&sysib, 0, sizeof(sysib)); 481defb0e31SAlexander Graf sysib.count = 1; 482defb0e31SAlexander Graf /* XXX change when SMP comes */ 483defb0e31SAlexander Graf stw_p(&sysib.vm[0].total_cpus, 1); 484defb0e31SAlexander Graf stw_p(&sysib.vm[0].conf_cpus, 1); 485defb0e31SAlexander Graf stw_p(&sysib.vm[0].standby_cpus, 0); 486defb0e31SAlexander Graf stw_p(&sysib.vm[0].reserved_cpus, 0); 487defb0e31SAlexander Graf ebcdic_put(sysib.vm[0].name, "KVMguest", 8); 488defb0e31SAlexander Graf stl_p(&sysib.vm[0].caf, 1000); 489defb0e31SAlexander Graf ebcdic_put(sysib.vm[0].cpi, "KVM/Linux ", 16); 490eb6282f2SStefan Weil cpu_physical_memory_write(a0, &sysib, sizeof(sysib)); 491defb0e31SAlexander Graf } else { 492defb0e31SAlexander Graf cc = 3; 493defb0e31SAlexander Graf } 494defb0e31SAlexander Graf break; 495defb0e31SAlexander Graf } 496defb0e31SAlexander Graf case STSI_LEVEL_CURRENT: 497defb0e31SAlexander Graf env->regs[0] = STSI_LEVEL_3; 498defb0e31SAlexander Graf break; 499defb0e31SAlexander Graf default: 500defb0e31SAlexander Graf cc = 3; 501defb0e31SAlexander Graf break; 502defb0e31SAlexander Graf } 503defb0e31SAlexander Graf 504defb0e31SAlexander Graf return cc; 505defb0e31SAlexander Graf } 506defb0e31SAlexander Graf 507089f5c06SBlue Swirl uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1, 508089f5c06SBlue Swirl uint64_t cpu_addr) 509defb0e31SAlexander Graf { 5105172b780SDavid Hildenbrand int cc = SIGP_CC_ORDER_CODE_ACCEPTED; 511defb0e31SAlexander Graf 512defb0e31SAlexander Graf HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n", 51371e47088SBlue Swirl __func__, order_code, r1, cpu_addr); 514defb0e31SAlexander Graf 515defb0e31SAlexander Graf /* Remember: Use "R1 or R1 + 1, whichever is the odd-numbered register" 516defb0e31SAlexander Graf as parameter (input). Status (output) is always R1. */ 517defb0e31SAlexander Graf 518defb0e31SAlexander Graf switch (order_code) { 519defb0e31SAlexander Graf case SIGP_SET_ARCH: 520defb0e31SAlexander Graf /* switch arch */ 521defb0e31SAlexander Graf break; 522defb0e31SAlexander Graf case SIGP_SENSE: 523defb0e31SAlexander Graf /* enumerate CPU status */ 524defb0e31SAlexander Graf if (cpu_addr) { 525defb0e31SAlexander Graf /* XXX implement when SMP comes */ 526defb0e31SAlexander Graf return 3; 527defb0e31SAlexander Graf } 528defb0e31SAlexander Graf env->regs[r1] &= 0xffffffff00000000ULL; 529defb0e31SAlexander Graf cc = 1; 530defb0e31SAlexander Graf break; 5311864b94aSAlexander Graf #if !defined(CONFIG_USER_ONLY) 5321864b94aSAlexander Graf case SIGP_RESTART: 5331864b94aSAlexander Graf qemu_system_reset_request(); 5345638d180SAndreas Färber cpu_loop_exit(CPU(s390_env_get_cpu(env))); 5351864b94aSAlexander Graf break; 5361864b94aSAlexander Graf case SIGP_STOP: 5371864b94aSAlexander Graf qemu_system_shutdown_request(); 5385638d180SAndreas Färber cpu_loop_exit(CPU(s390_env_get_cpu(env))); 5391864b94aSAlexander Graf break; 5401864b94aSAlexander Graf #endif 541defb0e31SAlexander Graf default: 542defb0e31SAlexander Graf /* unknown sigp */ 543defb0e31SAlexander Graf fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code); 5445172b780SDavid Hildenbrand cc = SIGP_CC_NOT_OPERATIONAL; 545defb0e31SAlexander Graf } 546defb0e31SAlexander Graf 547defb0e31SAlexander Graf return cc; 548defb0e31SAlexander Graf } 549defb0e31SAlexander Graf #endif 550ad8a4570SAlexander Graf 551ad8a4570SAlexander Graf #ifndef CONFIG_USER_ONLY 552ad8a4570SAlexander Graf void HELPER(xsch)(CPUS390XState *env, uint64_t r1) 553ad8a4570SAlexander Graf { 554ad8a4570SAlexander Graf S390CPU *cpu = s390_env_get_cpu(env); 555*278f5e98SAlex Bennée qemu_mutex_lock_iothread(); 556ad8a4570SAlexander Graf ioinst_handle_xsch(cpu, r1); 557*278f5e98SAlex Bennée qemu_mutex_unlock_iothread(); 558ad8a4570SAlexander Graf } 559ad8a4570SAlexander Graf 560ad8a4570SAlexander Graf void HELPER(csch)(CPUS390XState *env, uint64_t r1) 561ad8a4570SAlexander Graf { 562ad8a4570SAlexander Graf S390CPU *cpu = s390_env_get_cpu(env); 563*278f5e98SAlex Bennée qemu_mutex_lock_iothread(); 564ad8a4570SAlexander Graf ioinst_handle_csch(cpu, r1); 565*278f5e98SAlex Bennée qemu_mutex_unlock_iothread(); 566ad8a4570SAlexander Graf } 567ad8a4570SAlexander Graf 568ad8a4570SAlexander Graf void HELPER(hsch)(CPUS390XState *env, uint64_t r1) 569ad8a4570SAlexander Graf { 570ad8a4570SAlexander Graf S390CPU *cpu = s390_env_get_cpu(env); 571*278f5e98SAlex Bennée qemu_mutex_lock_iothread(); 572ad8a4570SAlexander Graf ioinst_handle_hsch(cpu, r1); 573*278f5e98SAlex Bennée qemu_mutex_unlock_iothread(); 574ad8a4570SAlexander Graf } 575ad8a4570SAlexander Graf 576ad8a4570SAlexander Graf void HELPER(msch)(CPUS390XState *env, uint64_t r1, uint64_t inst) 577ad8a4570SAlexander Graf { 578ad8a4570SAlexander Graf S390CPU *cpu = s390_env_get_cpu(env); 579*278f5e98SAlex Bennée qemu_mutex_lock_iothread(); 580ad8a4570SAlexander Graf ioinst_handle_msch(cpu, r1, inst >> 16); 581*278f5e98SAlex Bennée qemu_mutex_unlock_iothread(); 582ad8a4570SAlexander Graf } 583ad8a4570SAlexander Graf 584ad8a4570SAlexander Graf void HELPER(rchp)(CPUS390XState *env, uint64_t r1) 585ad8a4570SAlexander Graf { 586ad8a4570SAlexander Graf S390CPU *cpu = s390_env_get_cpu(env); 587*278f5e98SAlex Bennée qemu_mutex_lock_iothread(); 588ad8a4570SAlexander Graf ioinst_handle_rchp(cpu, r1); 589*278f5e98SAlex Bennée qemu_mutex_unlock_iothread(); 590ad8a4570SAlexander Graf } 591ad8a4570SAlexander Graf 592ad8a4570SAlexander Graf void HELPER(rsch)(CPUS390XState *env, uint64_t r1) 593ad8a4570SAlexander Graf { 594ad8a4570SAlexander Graf S390CPU *cpu = s390_env_get_cpu(env); 595*278f5e98SAlex Bennée qemu_mutex_lock_iothread(); 596ad8a4570SAlexander Graf ioinst_handle_rsch(cpu, r1); 597*278f5e98SAlex Bennée qemu_mutex_unlock_iothread(); 598ad8a4570SAlexander Graf } 599ad8a4570SAlexander Graf 600ad8a4570SAlexander Graf void HELPER(ssch)(CPUS390XState *env, uint64_t r1, uint64_t inst) 601ad8a4570SAlexander Graf { 602ad8a4570SAlexander Graf S390CPU *cpu = s390_env_get_cpu(env); 603*278f5e98SAlex Bennée qemu_mutex_lock_iothread(); 604ad8a4570SAlexander Graf ioinst_handle_ssch(cpu, r1, inst >> 16); 605*278f5e98SAlex Bennée qemu_mutex_unlock_iothread(); 606ad8a4570SAlexander Graf } 607ad8a4570SAlexander Graf 608ad8a4570SAlexander Graf void HELPER(stsch)(CPUS390XState *env, uint64_t r1, uint64_t inst) 609ad8a4570SAlexander Graf { 610ad8a4570SAlexander Graf S390CPU *cpu = s390_env_get_cpu(env); 611*278f5e98SAlex Bennée qemu_mutex_lock_iothread(); 612ad8a4570SAlexander Graf ioinst_handle_stsch(cpu, r1, inst >> 16); 613*278f5e98SAlex Bennée qemu_mutex_unlock_iothread(); 614ad8a4570SAlexander Graf } 615ad8a4570SAlexander Graf 616ad8a4570SAlexander Graf void HELPER(tsch)(CPUS390XState *env, uint64_t r1, uint64_t inst) 617ad8a4570SAlexander Graf { 618ad8a4570SAlexander Graf S390CPU *cpu = s390_env_get_cpu(env); 619*278f5e98SAlex Bennée qemu_mutex_lock_iothread(); 620ad8a4570SAlexander Graf ioinst_handle_tsch(cpu, r1, inst >> 16); 621*278f5e98SAlex Bennée qemu_mutex_unlock_iothread(); 622ad8a4570SAlexander Graf } 623ad8a4570SAlexander Graf 624ad8a4570SAlexander Graf void HELPER(chsc)(CPUS390XState *env, uint64_t inst) 625ad8a4570SAlexander Graf { 626ad8a4570SAlexander Graf S390CPU *cpu = s390_env_get_cpu(env); 627*278f5e98SAlex Bennée qemu_mutex_lock_iothread(); 628ad8a4570SAlexander Graf ioinst_handle_chsc(cpu, inst >> 16); 629*278f5e98SAlex Bennée qemu_mutex_unlock_iothread(); 630ad8a4570SAlexander Graf } 631ad8a4570SAlexander Graf #endif 632777c98c3SAurelien Jarno 633777c98c3SAurelien Jarno #ifndef CONFIG_USER_ONLY 634777c98c3SAurelien Jarno void HELPER(per_check_exception)(CPUS390XState *env) 635777c98c3SAurelien Jarno { 636777c98c3SAurelien Jarno CPUState *cs = CPU(s390_env_get_cpu(env)); 637777c98c3SAurelien Jarno 638777c98c3SAurelien Jarno if (env->per_perc_atmid) { 639777c98c3SAurelien Jarno env->int_pgm_code = PGM_PER; 640777c98c3SAurelien Jarno env->int_pgm_ilen = get_ilen(cpu_ldub_code(env, env->per_address)); 641777c98c3SAurelien Jarno 642777c98c3SAurelien Jarno cs->exception_index = EXCP_PGM; 643777c98c3SAurelien Jarno cpu_loop_exit(cs); 644777c98c3SAurelien Jarno } 645777c98c3SAurelien Jarno } 6462c2275ebSAurelien Jarno 6472c2275ebSAurelien Jarno void HELPER(per_branch)(CPUS390XState *env, uint64_t from, uint64_t to) 6482c2275ebSAurelien Jarno { 6492c2275ebSAurelien Jarno if ((env->cregs[9] & PER_CR9_EVENT_BRANCH)) { 6502c2275ebSAurelien Jarno if (!(env->cregs[9] & PER_CR9_CONTROL_BRANCH_ADDRESS) 6512c2275ebSAurelien Jarno || get_per_in_range(env, to)) { 6522c2275ebSAurelien Jarno env->per_address = from; 6532c2275ebSAurelien Jarno env->per_perc_atmid = PER_CODE_EVENT_BRANCH | get_per_atmid(env); 6542c2275ebSAurelien Jarno } 6552c2275ebSAurelien Jarno } 6562c2275ebSAurelien Jarno } 657f0e0d817SAurelien Jarno 658f0e0d817SAurelien Jarno void HELPER(per_ifetch)(CPUS390XState *env, uint64_t addr) 659f0e0d817SAurelien Jarno { 660f0e0d817SAurelien Jarno if ((env->cregs[9] & PER_CR9_EVENT_IFETCH) && get_per_in_range(env, addr)) { 661f0e0d817SAurelien Jarno env->per_address = addr; 662f0e0d817SAurelien Jarno env->per_perc_atmid = PER_CODE_EVENT_IFETCH | get_per_atmid(env); 66383bb1612SAurelien Jarno 66483bb1612SAurelien Jarno /* If the instruction has to be nullified, trigger the 66583bb1612SAurelien Jarno exception immediately. */ 66683bb1612SAurelien Jarno if (env->cregs[9] & PER_CR9_EVENT_NULLIFICATION) { 66783bb1612SAurelien Jarno CPUState *cs = CPU(s390_env_get_cpu(env)); 66883bb1612SAurelien Jarno 66983bb1612SAurelien Jarno env->int_pgm_code = PGM_PER; 67083bb1612SAurelien Jarno env->int_pgm_ilen = get_ilen(cpu_ldub_code(env, addr)); 67183bb1612SAurelien Jarno 67283bb1612SAurelien Jarno cs->exception_index = EXCP_PGM; 67383bb1612SAurelien Jarno cpu_loop_exit(cs); 67483bb1612SAurelien Jarno } 675f0e0d817SAurelien Jarno } 676f0e0d817SAurelien Jarno } 677777c98c3SAurelien Jarno #endif 678