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" 223e457172SBlue Swirl #include "cpu.h" 23022c62cbSPaolo Bonzini #include "exec/memory.h" 241de7afc9SPaolo Bonzini #include "qemu/host-utils.h" 252ef6175aSRichard Henderson #include "exec/helper-proto.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 3263c91552SPaolo Bonzini #include "exec/exec-all.h" 33f08b6170SPaolo Bonzini #include "exec/cpu_ldst.h" 3410ec5117SAlexander Graf 351864b94aSAlexander Graf #if !defined(CONFIG_USER_ONLY) 36741da0d3SPaolo Bonzini #include "hw/watchdog/wdt_diag288.h" 37f0778475SChristian Borntraeger #include "sysemu/cpus.h" 389c17d615SPaolo Bonzini #include "sysemu/sysemu.h" 3940fa5264SHeinz Graalfs #include "hw/s390x/ebcdic.h" 40df75a4e2SFan Zhang #include "hw/s390x/ipl.h" 4110ec5117SAlexander Graf #endif 42d5a43964SAlexander Graf 43defb0e31SAlexander Graf /* #define DEBUG_HELPER */ 44defb0e31SAlexander Graf #ifdef DEBUG_HELPER 45defb0e31SAlexander Graf #define HELPER_LOG(x...) qemu_log(x) 46defb0e31SAlexander Graf #else 47defb0e31SAlexander Graf #define HELPER_LOG(x...) 48defb0e31SAlexander Graf #endif 49defb0e31SAlexander Graf 50b4e2bd35SRichard Henderson /* Raise an exception dynamically from a helper function. */ 51b4e2bd35SRichard Henderson void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp, 52b4e2bd35SRichard Henderson uintptr_t retaddr) 53b4e2bd35SRichard Henderson { 5427103424SAndreas Färber CPUState *cs = CPU(s390_env_get_cpu(env)); 55b4e2bd35SRichard Henderson int t; 56b4e2bd35SRichard Henderson 5727103424SAndreas Färber cs->exception_index = EXCP_PGM; 58b4e2bd35SRichard Henderson env->int_pgm_code = excp; 59b4e2bd35SRichard Henderson 60b4e2bd35SRichard Henderson /* Use the (ultimate) callers address to find the insn that trapped. */ 613f38f309SAndreas Färber cpu_restore_state(cs, retaddr); 62b4e2bd35SRichard Henderson 63b4e2bd35SRichard Henderson /* Advance past the insn. */ 64b4e2bd35SRichard Henderson t = cpu_ldub_code(env, env->psw.addr); 65b4e2bd35SRichard Henderson env->int_pgm_ilen = t = get_ilen(t); 669bebf986SAurelien Jarno env->psw.addr += t; 67b4e2bd35SRichard Henderson 685638d180SAndreas Färber cpu_loop_exit(cs); 69b4e2bd35SRichard Henderson } 70b4e2bd35SRichard Henderson 71d5a103cdSRichard Henderson /* Raise an exception statically from a TB. */ 72089f5c06SBlue Swirl void HELPER(exception)(CPUS390XState *env, uint32_t excp) 73defb0e31SAlexander Graf { 7427103424SAndreas Färber CPUState *cs = CPU(s390_env_get_cpu(env)); 7527103424SAndreas Färber 7671e47088SBlue Swirl HELPER_LOG("%s: exception %d\n", __func__, excp); 7727103424SAndreas Färber cs->exception_index = excp; 785638d180SAndreas Färber cpu_loop_exit(cs); 79defb0e31SAlexander Graf } 80defb0e31SAlexander Graf 81defb0e31SAlexander Graf #ifndef CONFIG_USER_ONLY 82a158986dSStefan Weil 83d5a103cdSRichard Henderson void program_interrupt(CPUS390XState *env, uint32_t code, int ilen) 84defb0e31SAlexander Graf { 8527103424SAndreas Färber S390CPU *cpu = s390_env_get_cpu(env); 8627103424SAndreas Färber 870d404541SRichard Henderson qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n", 880d404541SRichard Henderson env->psw.addr); 89defb0e31SAlexander Graf 90defb0e31SAlexander Graf if (kvm_enabled()) { 91af2be207SJan Kiszka #ifdef CONFIG_KVM 92de13d216SCornelia Huck struct kvm_s390_irq irq = { 93de13d216SCornelia Huck .type = KVM_S390_PROGRAM_INT, 94de13d216SCornelia Huck .u.pgm.code = code, 95de13d216SCornelia Huck }; 96de13d216SCornelia Huck 97de13d216SCornelia Huck kvm_s390_vcpu_interrupt(cpu, &irq); 98af2be207SJan Kiszka #endif 99defb0e31SAlexander Graf } else { 10027103424SAndreas Färber CPUState *cs = CPU(cpu); 10127103424SAndreas Färber 102defb0e31SAlexander Graf env->int_pgm_code = code; 103d5a103cdSRichard Henderson env->int_pgm_ilen = ilen; 10427103424SAndreas Färber cs->exception_index = EXCP_PGM; 1055638d180SAndreas Färber cpu_loop_exit(cs); 106defb0e31SAlexander Graf } 107defb0e31SAlexander Graf } 108defb0e31SAlexander Graf 109defb0e31SAlexander Graf /* SCLP service call */ 110dc458df9SRichard Henderson uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2) 111defb0e31SAlexander Graf { 1126e252802SThomas Huth int r = sclp_service_call(env, r1, r2); 1139abf567dSChristian Borntraeger if (r < 0) { 1149abf567dSChristian Borntraeger program_interrupt(env, -r, 4); 115d5a43964SAlexander Graf return 0; 116d5a43964SAlexander Graf } 1179abf567dSChristian Borntraeger return r; 1189abf567dSChristian Borntraeger } 119defb0e31SAlexander Graf 120268846baSEugene (jno) Dvurechenski #ifndef CONFIG_USER_ONLY 121d8b30c83SChristian Borntraeger static int modified_clear_reset(S390CPU *cpu) 122d8b30c83SChristian Borntraeger { 123d8b30c83SChristian Borntraeger S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); 12485ca3371SDavid Hildenbrand CPUState *t; 125d8b30c83SChristian Borntraeger 126d8b30c83SChristian Borntraeger pause_all_vcpus(); 127d8b30c83SChristian Borntraeger cpu_synchronize_all_states(); 12885ca3371SDavid Hildenbrand CPU_FOREACH(t) { 12914e6fe12SPaolo Bonzini run_on_cpu(t, s390_do_cpu_full_reset, RUN_ON_CPU_NULL); 13085ca3371SDavid Hildenbrand } 1311cd4e0f6SDavid Hildenbrand s390_cmma_reset(); 132d9f090ecSDavid Hildenbrand subsystem_reset(); 1334ab72920SDavid Hildenbrand s390_crypto_reset(); 134d8b30c83SChristian Borntraeger scc->load_normal(CPU(cpu)); 135d8b30c83SChristian Borntraeger cpu_synchronize_all_post_reset(); 136d8b30c83SChristian Borntraeger resume_all_vcpus(); 137d8b30c83SChristian Borntraeger return 0; 138d8b30c83SChristian Borntraeger } 139d8b30c83SChristian Borntraeger 140f0778475SChristian Borntraeger static int load_normal_reset(S390CPU *cpu) 141f0778475SChristian Borntraeger { 142f0778475SChristian Borntraeger S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); 14385ca3371SDavid Hildenbrand CPUState *t; 144f0778475SChristian Borntraeger 145f0778475SChristian Borntraeger pause_all_vcpus(); 146f0778475SChristian Borntraeger cpu_synchronize_all_states(); 14785ca3371SDavid Hildenbrand CPU_FOREACH(t) { 14814e6fe12SPaolo Bonzini run_on_cpu(t, s390_do_cpu_reset, RUN_ON_CPU_NULL); 14985ca3371SDavid Hildenbrand } 1501cd4e0f6SDavid Hildenbrand s390_cmma_reset(); 151d9f090ecSDavid Hildenbrand subsystem_reset(); 152f0778475SChristian Borntraeger scc->initial_cpu_reset(CPU(cpu)); 153f0778475SChristian Borntraeger scc->load_normal(CPU(cpu)); 154f0778475SChristian Borntraeger cpu_synchronize_all_post_reset(); 155f0778475SChristian Borntraeger resume_all_vcpus(); 156f0778475SChristian Borntraeger return 0; 157f0778475SChristian Borntraeger } 158f0778475SChristian Borntraeger 1598fc639afSXu Wang int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3) 1608fc639afSXu Wang { 1618fc639afSXu Wang uint64_t func = env->regs[r1]; 1628fc639afSXu Wang uint64_t timeout = env->regs[r1 + 1]; 1638fc639afSXu Wang uint64_t action = env->regs[r3]; 1648fc639afSXu Wang Object *obj; 1658fc639afSXu Wang DIAG288State *diag288; 1668fc639afSXu Wang DIAG288Class *diag288_class; 1678fc639afSXu Wang 1688fc639afSXu Wang if (r1 % 2 || action != 0) { 1698fc639afSXu Wang return -1; 1708fc639afSXu Wang } 1718fc639afSXu Wang 1728fc639afSXu Wang /* Timeout must be more than 15 seconds except for timer deletion */ 1738fc639afSXu Wang if (func != WDT_DIAG288_CANCEL && timeout < 15) { 1748fc639afSXu Wang return -1; 1758fc639afSXu Wang } 1768fc639afSXu Wang 1778fc639afSXu Wang obj = object_resolve_path_type("", TYPE_WDT_DIAG288, NULL); 1788fc639afSXu Wang if (!obj) { 1798fc639afSXu Wang return -1; 1808fc639afSXu Wang } 1818fc639afSXu Wang 1828fc639afSXu Wang diag288 = DIAG288(obj); 1838fc639afSXu Wang diag288_class = DIAG288_GET_CLASS(diag288); 1848fc639afSXu Wang return diag288_class->handle_timer(diag288, func, timeout); 1858fc639afSXu Wang } 1868fc639afSXu Wang 187df75a4e2SFan Zhang #define DIAG_308_RC_OK 0x0001 188268846baSEugene (jno) Dvurechenski #define DIAG_308_RC_NO_CONF 0x0102 189268846baSEugene (jno) Dvurechenski #define DIAG_308_RC_INVALID 0x0402 190df75a4e2SFan Zhang 191268846baSEugene (jno) Dvurechenski void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3) 192268846baSEugene (jno) Dvurechenski { 193268846baSEugene (jno) Dvurechenski uint64_t addr = env->regs[r1]; 194268846baSEugene (jno) Dvurechenski uint64_t subcode = env->regs[r3]; 195df75a4e2SFan Zhang IplParameterBlock *iplb; 196268846baSEugene (jno) Dvurechenski 197268846baSEugene (jno) Dvurechenski if (env->psw.mask & PSW_MASK_PSTATE) { 198268846baSEugene (jno) Dvurechenski program_interrupt(env, PGM_PRIVILEGED, ILEN_LATER_INC); 199268846baSEugene (jno) Dvurechenski return; 200268846baSEugene (jno) Dvurechenski } 201268846baSEugene (jno) Dvurechenski 202268846baSEugene (jno) Dvurechenski if ((subcode & ~0x0ffffULL) || (subcode > 6)) { 203268846baSEugene (jno) Dvurechenski program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC); 204268846baSEugene (jno) Dvurechenski return; 205268846baSEugene (jno) Dvurechenski } 206268846baSEugene (jno) Dvurechenski 207268846baSEugene (jno) Dvurechenski switch (subcode) { 208d8b30c83SChristian Borntraeger case 0: 209d8b30c83SChristian Borntraeger modified_clear_reset(s390_env_get_cpu(env)); 2108df7eef3SAurelien Jarno if (tcg_enabled()) { 2118df7eef3SAurelien Jarno cpu_loop_exit(CPU(s390_env_get_cpu(env))); 2128df7eef3SAurelien Jarno } 213d8b30c83SChristian Borntraeger break; 214f0778475SChristian Borntraeger case 1: 215f0778475SChristian Borntraeger load_normal_reset(s390_env_get_cpu(env)); 2168df7eef3SAurelien Jarno if (tcg_enabled()) { 2178df7eef3SAurelien Jarno cpu_loop_exit(CPU(s390_env_get_cpu(env))); 2188df7eef3SAurelien Jarno } 219f0778475SChristian Borntraeger break; 2202ecacb0bSAurelien Jarno case 3: 2212ecacb0bSAurelien Jarno s390_reipl_request(); 2222ecacb0bSAurelien Jarno if (tcg_enabled()) { 2232ecacb0bSAurelien Jarno cpu_loop_exit(CPU(s390_env_get_cpu(env))); 2242ecacb0bSAurelien Jarno } 2252ecacb0bSAurelien Jarno break; 226268846baSEugene (jno) Dvurechenski case 5: 227268846baSEugene (jno) Dvurechenski if ((r1 & 1) || (addr & 0x0fffULL)) { 228268846baSEugene (jno) Dvurechenski program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC); 229268846baSEugene (jno) Dvurechenski return; 230268846baSEugene (jno) Dvurechenski } 231df75a4e2SFan Zhang if (!address_space_access_valid(&address_space_memory, addr, 232df75a4e2SFan Zhang sizeof(IplParameterBlock), false)) { 233df75a4e2SFan Zhang program_interrupt(env, PGM_ADDRESSING, ILEN_LATER_INC); 234df75a4e2SFan Zhang return; 235df75a4e2SFan Zhang } 23604ca4b92SAlexander Yarygin iplb = g_malloc0(sizeof(IplParameterBlock)); 2379946a911SAlexander Yarygin cpu_physical_memory_read(addr, iplb, sizeof(iplb->len)); 2389946a911SAlexander Yarygin if (!iplb_valid_len(iplb)) { 2399946a911SAlexander Yarygin env->regs[r1 + 1] = DIAG_308_RC_INVALID; 2409946a911SAlexander Yarygin goto out; 2419946a911SAlexander Yarygin } 2429946a911SAlexander Yarygin 2439946a911SAlexander Yarygin cpu_physical_memory_read(addr, iplb, be32_to_cpu(iplb->len)); 2449946a911SAlexander Yarygin 2459946a911SAlexander Yarygin if (!iplb_valid_ccw(iplb) && !iplb_valid_fcp(iplb)) { 2469946a911SAlexander Yarygin env->regs[r1 + 1] = DIAG_308_RC_INVALID; 2479946a911SAlexander Yarygin goto out; 2489946a911SAlexander Yarygin } 2499946a911SAlexander Yarygin 250feacc6c2SDavid Hildenbrand s390_ipl_update_diag308(iplb); 251df75a4e2SFan Zhang env->regs[r1 + 1] = DIAG_308_RC_OK; 2529946a911SAlexander Yarygin out: 253df75a4e2SFan Zhang g_free(iplb); 254268846baSEugene (jno) Dvurechenski return; 255268846baSEugene (jno) Dvurechenski case 6: 256268846baSEugene (jno) Dvurechenski if ((r1 & 1) || (addr & 0x0fffULL)) { 257268846baSEugene (jno) Dvurechenski program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC); 258268846baSEugene (jno) Dvurechenski return; 259268846baSEugene (jno) Dvurechenski } 260df75a4e2SFan Zhang if (!address_space_access_valid(&address_space_memory, addr, 261df75a4e2SFan Zhang sizeof(IplParameterBlock), true)) { 262df75a4e2SFan Zhang program_interrupt(env, PGM_ADDRESSING, ILEN_LATER_INC); 263df75a4e2SFan Zhang return; 264df75a4e2SFan Zhang } 265df75a4e2SFan Zhang iplb = s390_ipl_get_iplb(); 266df75a4e2SFan Zhang if (iplb) { 2679946a911SAlexander Yarygin cpu_physical_memory_write(addr, iplb, be32_to_cpu(iplb->len)); 268df75a4e2SFan Zhang env->regs[r1 + 1] = DIAG_308_RC_OK; 269df75a4e2SFan Zhang } else { 270268846baSEugene (jno) Dvurechenski env->regs[r1 + 1] = DIAG_308_RC_NO_CONF; 271df75a4e2SFan Zhang } 272268846baSEugene (jno) Dvurechenski return; 273268846baSEugene (jno) Dvurechenski default: 274268846baSEugene (jno) Dvurechenski hw_error("Unhandled diag308 subcode %" PRIx64, subcode); 275268846baSEugene (jno) Dvurechenski break; 276268846baSEugene (jno) Dvurechenski } 277268846baSEugene (jno) Dvurechenski } 278268846baSEugene (jno) Dvurechenski #endif 279268846baSEugene (jno) Dvurechenski 2808df7eef3SAurelien Jarno void HELPER(diag)(CPUS390XState *env, uint32_t r1, uint32_t r3, uint32_t num) 281defb0e31SAlexander Graf { 282defb0e31SAlexander Graf uint64_t r; 283defb0e31SAlexander Graf 284defb0e31SAlexander Graf switch (num) { 285defb0e31SAlexander Graf case 0x500: 286defb0e31SAlexander Graf /* KVM hypercall */ 28728e942f8SCornelia Huck r = s390_virtio_hypercall(env); 288defb0e31SAlexander Graf break; 289defb0e31SAlexander Graf case 0x44: 290defb0e31SAlexander Graf /* yield */ 291defb0e31SAlexander Graf r = 0; 292defb0e31SAlexander Graf break; 293defb0e31SAlexander Graf case 0x308: 294defb0e31SAlexander Graf /* ipl */ 2958df7eef3SAurelien Jarno handle_diag_308(env, r1, r3); 296defb0e31SAlexander Graf r = 0; 297defb0e31SAlexander Graf break; 298defb0e31SAlexander Graf default: 299defb0e31SAlexander Graf r = -1; 300defb0e31SAlexander Graf break; 301defb0e31SAlexander Graf } 302defb0e31SAlexander Graf 303defb0e31SAlexander Graf if (r) { 304d5a103cdSRichard Henderson program_interrupt(env, PGM_OPERATION, ILEN_LATER_INC); 305defb0e31SAlexander Graf } 306defb0e31SAlexander Graf } 307defb0e31SAlexander Graf 308defb0e31SAlexander Graf /* Set Prefix */ 309089f5c06SBlue Swirl void HELPER(spx)(CPUS390XState *env, uint64_t a1) 310defb0e31SAlexander Graf { 31131b030d4SAndreas Färber CPUState *cs = CPU(s390_env_get_cpu(env)); 312e805a0d3SRichard Henderson uint32_t prefix = a1 & 0x7fffe000; 31331b030d4SAndreas Färber 314e805a0d3SRichard Henderson env->psa = prefix; 315aafcf80eSPaolo Bonzini HELPER_LOG("prefix: %#x\n", prefix); 31631b030d4SAndreas Färber tlb_flush_page(cs, 0); 31731b030d4SAndreas Färber tlb_flush_page(cs, TARGET_PAGE_SIZE); 318defb0e31SAlexander Graf } 319defb0e31SAlexander Graf 320d9d55f11SAurelien Jarno /* Store Clock */ 321d9d55f11SAurelien Jarno uint64_t HELPER(stck)(CPUS390XState *env) 322defb0e31SAlexander Graf { 323defb0e31SAlexander Graf uint64_t time; 324defb0e31SAlexander Graf 325defb0e31SAlexander Graf time = env->tod_offset + 326bc72ad67SAlex Bligh time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - env->tod_basetime); 327defb0e31SAlexander Graf 328defb0e31SAlexander Graf return time; 329defb0e31SAlexander Graf } 330defb0e31SAlexander Graf 331defb0e31SAlexander Graf /* Set Clock Comparator */ 332dd3eb7b5SRichard Henderson void HELPER(sckc)(CPUS390XState *env, uint64_t time) 333defb0e31SAlexander Graf { 334defb0e31SAlexander Graf if (time == -1ULL) { 335defb0e31SAlexander Graf return; 336defb0e31SAlexander Graf } 337defb0e31SAlexander Graf 338aa9e14e6SAurelien Jarno env->ckc = time; 339aa9e14e6SAurelien Jarno 340c941f074SAurelien Jarno /* difference between origins */ 341c941f074SAurelien Jarno time -= env->tod_offset; 342c941f074SAurelien Jarno 343defb0e31SAlexander Graf /* nanoseconds */ 3449cb32c44SAurelien Jarno time = tod2time(time); 345defb0e31SAlexander Graf 346c941f074SAurelien Jarno timer_mod(env->tod_timer, env->tod_basetime + time); 347defb0e31SAlexander Graf } 348defb0e31SAlexander Graf 349defb0e31SAlexander Graf /* Store Clock Comparator */ 350dd3eb7b5SRichard Henderson uint64_t HELPER(stckc)(CPUS390XState *env) 351defb0e31SAlexander Graf { 352aa9e14e6SAurelien Jarno return env->ckc; 353defb0e31SAlexander Graf } 354defb0e31SAlexander Graf 355defb0e31SAlexander Graf /* Set CPU Timer */ 356c4f0a863SRichard Henderson void HELPER(spt)(CPUS390XState *env, uint64_t time) 357defb0e31SAlexander Graf { 358defb0e31SAlexander Graf if (time == -1ULL) { 359defb0e31SAlexander Graf return; 360defb0e31SAlexander Graf } 361defb0e31SAlexander Graf 362defb0e31SAlexander Graf /* nanoseconds */ 3639cb32c44SAurelien Jarno time = tod2time(time); 364defb0e31SAlexander Graf 365b8ae94bdSAurelien Jarno env->cputm = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time; 366b8ae94bdSAurelien Jarno 367b8ae94bdSAurelien Jarno timer_mod(env->cpu_timer, env->cputm); 368defb0e31SAlexander Graf } 369defb0e31SAlexander Graf 370defb0e31SAlexander Graf /* Store CPU Timer */ 371c4f0a863SRichard Henderson uint64_t HELPER(stpt)(CPUS390XState *env) 372defb0e31SAlexander Graf { 373b8ae94bdSAurelien Jarno return time2tod(env->cputm - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); 374defb0e31SAlexander Graf } 375defb0e31SAlexander Graf 376defb0e31SAlexander Graf /* Store System Information */ 377d14b3e09SRichard Henderson uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, 378d14b3e09SRichard Henderson uint64_t r0, uint64_t r1) 379defb0e31SAlexander Graf { 380defb0e31SAlexander Graf int cc = 0; 381defb0e31SAlexander Graf int sel1, sel2; 382defb0e31SAlexander Graf 383defb0e31SAlexander Graf if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 && 384defb0e31SAlexander Graf ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) { 385defb0e31SAlexander Graf /* valid function code, invalid reserved bits */ 386defb0e31SAlexander Graf program_interrupt(env, PGM_SPECIFICATION, 2); 387defb0e31SAlexander Graf } 388defb0e31SAlexander Graf 389defb0e31SAlexander Graf sel1 = r0 & STSI_R0_SEL1_MASK; 390defb0e31SAlexander Graf sel2 = r1 & STSI_R1_SEL2_MASK; 391defb0e31SAlexander Graf 392defb0e31SAlexander Graf /* XXX: spec exception if sysib is not 4k-aligned */ 393defb0e31SAlexander Graf 394defb0e31SAlexander Graf switch (r0 & STSI_LEVEL_MASK) { 395defb0e31SAlexander Graf case STSI_LEVEL_1: 396defb0e31SAlexander Graf if ((sel1 == 1) && (sel2 == 1)) { 397defb0e31SAlexander Graf /* Basic Machine Configuration */ 398defb0e31SAlexander Graf struct sysib_111 sysib; 399defb0e31SAlexander Graf 400defb0e31SAlexander Graf memset(&sysib, 0, sizeof(sysib)); 401defb0e31SAlexander Graf ebcdic_put(sysib.manuf, "QEMU ", 16); 402defb0e31SAlexander Graf /* same as machine type number in STORE CPU ID */ 403defb0e31SAlexander Graf ebcdic_put(sysib.type, "QEMU", 4); 404defb0e31SAlexander Graf /* same as model number in STORE CPU ID */ 405defb0e31SAlexander Graf ebcdic_put(sysib.model, "QEMU ", 16); 406defb0e31SAlexander Graf ebcdic_put(sysib.sequence, "QEMU ", 16); 407defb0e31SAlexander Graf ebcdic_put(sysib.plant, "QEMU", 4); 408eb6282f2SStefan Weil cpu_physical_memory_write(a0, &sysib, sizeof(sysib)); 409defb0e31SAlexander Graf } else if ((sel1 == 2) && (sel2 == 1)) { 410defb0e31SAlexander Graf /* Basic Machine CPU */ 411defb0e31SAlexander Graf struct sysib_121 sysib; 412defb0e31SAlexander Graf 413defb0e31SAlexander Graf memset(&sysib, 0, sizeof(sysib)); 414defb0e31SAlexander Graf /* XXX make different for different CPUs? */ 415defb0e31SAlexander Graf ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16); 416defb0e31SAlexander Graf ebcdic_put(sysib.plant, "QEMU", 4); 417defb0e31SAlexander Graf stw_p(&sysib.cpu_addr, env->cpu_num); 418eb6282f2SStefan Weil cpu_physical_memory_write(a0, &sysib, sizeof(sysib)); 419defb0e31SAlexander Graf } else if ((sel1 == 2) && (sel2 == 2)) { 420defb0e31SAlexander Graf /* Basic Machine CPUs */ 421defb0e31SAlexander Graf struct sysib_122 sysib; 422defb0e31SAlexander Graf 423defb0e31SAlexander Graf memset(&sysib, 0, sizeof(sysib)); 424defb0e31SAlexander Graf stl_p(&sysib.capability, 0x443afc29); 425defb0e31SAlexander Graf /* XXX change when SMP comes */ 426defb0e31SAlexander Graf stw_p(&sysib.total_cpus, 1); 427defb0e31SAlexander Graf stw_p(&sysib.active_cpus, 1); 428defb0e31SAlexander Graf stw_p(&sysib.standby_cpus, 0); 429defb0e31SAlexander Graf stw_p(&sysib.reserved_cpus, 0); 430eb6282f2SStefan Weil cpu_physical_memory_write(a0, &sysib, sizeof(sysib)); 431defb0e31SAlexander Graf } else { 432defb0e31SAlexander Graf cc = 3; 433defb0e31SAlexander Graf } 434defb0e31SAlexander Graf break; 435defb0e31SAlexander Graf case STSI_LEVEL_2: 436defb0e31SAlexander Graf { 437defb0e31SAlexander Graf if ((sel1 == 2) && (sel2 == 1)) { 438defb0e31SAlexander Graf /* LPAR CPU */ 439defb0e31SAlexander Graf struct sysib_221 sysib; 440defb0e31SAlexander Graf 441defb0e31SAlexander Graf memset(&sysib, 0, sizeof(sysib)); 442defb0e31SAlexander Graf /* XXX make different for different CPUs? */ 443defb0e31SAlexander Graf ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16); 444defb0e31SAlexander Graf ebcdic_put(sysib.plant, "QEMU", 4); 445defb0e31SAlexander Graf stw_p(&sysib.cpu_addr, env->cpu_num); 446defb0e31SAlexander Graf stw_p(&sysib.cpu_id, 0); 447eb6282f2SStefan Weil cpu_physical_memory_write(a0, &sysib, sizeof(sysib)); 448defb0e31SAlexander Graf } else if ((sel1 == 2) && (sel2 == 2)) { 449defb0e31SAlexander Graf /* LPAR CPUs */ 450defb0e31SAlexander Graf struct sysib_222 sysib; 451defb0e31SAlexander Graf 452defb0e31SAlexander Graf memset(&sysib, 0, sizeof(sysib)); 453defb0e31SAlexander Graf stw_p(&sysib.lpar_num, 0); 454defb0e31SAlexander Graf sysib.lcpuc = 0; 455defb0e31SAlexander Graf /* XXX change when SMP comes */ 456defb0e31SAlexander Graf stw_p(&sysib.total_cpus, 1); 457defb0e31SAlexander Graf stw_p(&sysib.conf_cpus, 1); 458defb0e31SAlexander Graf stw_p(&sysib.standby_cpus, 0); 459defb0e31SAlexander Graf stw_p(&sysib.reserved_cpus, 0); 460defb0e31SAlexander Graf ebcdic_put(sysib.name, "QEMU ", 8); 461defb0e31SAlexander Graf stl_p(&sysib.caf, 1000); 462defb0e31SAlexander Graf stw_p(&sysib.dedicated_cpus, 0); 463defb0e31SAlexander Graf stw_p(&sysib.shared_cpus, 0); 464eb6282f2SStefan Weil cpu_physical_memory_write(a0, &sysib, sizeof(sysib)); 465defb0e31SAlexander Graf } else { 466defb0e31SAlexander Graf cc = 3; 467defb0e31SAlexander Graf } 468defb0e31SAlexander Graf break; 469defb0e31SAlexander Graf } 470defb0e31SAlexander Graf case STSI_LEVEL_3: 471defb0e31SAlexander Graf { 472defb0e31SAlexander Graf if ((sel1 == 2) && (sel2 == 2)) { 473defb0e31SAlexander Graf /* VM CPUs */ 474defb0e31SAlexander Graf struct sysib_322 sysib; 475defb0e31SAlexander Graf 476defb0e31SAlexander Graf memset(&sysib, 0, sizeof(sysib)); 477defb0e31SAlexander Graf sysib.count = 1; 478defb0e31SAlexander Graf /* XXX change when SMP comes */ 479defb0e31SAlexander Graf stw_p(&sysib.vm[0].total_cpus, 1); 480defb0e31SAlexander Graf stw_p(&sysib.vm[0].conf_cpus, 1); 481defb0e31SAlexander Graf stw_p(&sysib.vm[0].standby_cpus, 0); 482defb0e31SAlexander Graf stw_p(&sysib.vm[0].reserved_cpus, 0); 483defb0e31SAlexander Graf ebcdic_put(sysib.vm[0].name, "KVMguest", 8); 484defb0e31SAlexander Graf stl_p(&sysib.vm[0].caf, 1000); 485defb0e31SAlexander Graf ebcdic_put(sysib.vm[0].cpi, "KVM/Linux ", 16); 486eb6282f2SStefan Weil cpu_physical_memory_write(a0, &sysib, sizeof(sysib)); 487defb0e31SAlexander Graf } else { 488defb0e31SAlexander Graf cc = 3; 489defb0e31SAlexander Graf } 490defb0e31SAlexander Graf break; 491defb0e31SAlexander Graf } 492defb0e31SAlexander Graf case STSI_LEVEL_CURRENT: 493defb0e31SAlexander Graf env->regs[0] = STSI_LEVEL_3; 494defb0e31SAlexander Graf break; 495defb0e31SAlexander Graf default: 496defb0e31SAlexander Graf cc = 3; 497defb0e31SAlexander Graf break; 498defb0e31SAlexander Graf } 499defb0e31SAlexander Graf 500defb0e31SAlexander Graf return cc; 501defb0e31SAlexander Graf } 502defb0e31SAlexander Graf 503089f5c06SBlue Swirl uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1, 504089f5c06SBlue Swirl uint64_t cpu_addr) 505defb0e31SAlexander Graf { 5065172b780SDavid Hildenbrand int cc = SIGP_CC_ORDER_CODE_ACCEPTED; 507defb0e31SAlexander Graf 508defb0e31SAlexander Graf HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n", 50971e47088SBlue Swirl __func__, order_code, r1, cpu_addr); 510defb0e31SAlexander Graf 511defb0e31SAlexander Graf /* Remember: Use "R1 or R1 + 1, whichever is the odd-numbered register" 512defb0e31SAlexander Graf as parameter (input). Status (output) is always R1. */ 513defb0e31SAlexander Graf 514defb0e31SAlexander Graf switch (order_code) { 515defb0e31SAlexander Graf case SIGP_SET_ARCH: 516defb0e31SAlexander Graf /* switch arch */ 517defb0e31SAlexander Graf break; 518defb0e31SAlexander Graf case SIGP_SENSE: 519defb0e31SAlexander Graf /* enumerate CPU status */ 520defb0e31SAlexander Graf if (cpu_addr) { 521defb0e31SAlexander Graf /* XXX implement when SMP comes */ 522defb0e31SAlexander Graf return 3; 523defb0e31SAlexander Graf } 524defb0e31SAlexander Graf env->regs[r1] &= 0xffffffff00000000ULL; 525defb0e31SAlexander Graf cc = 1; 526defb0e31SAlexander Graf break; 5271864b94aSAlexander Graf #if !defined(CONFIG_USER_ONLY) 5281864b94aSAlexander Graf case SIGP_RESTART: 5291864b94aSAlexander Graf qemu_system_reset_request(); 5305638d180SAndreas Färber cpu_loop_exit(CPU(s390_env_get_cpu(env))); 5311864b94aSAlexander Graf break; 5321864b94aSAlexander Graf case SIGP_STOP: 5331864b94aSAlexander Graf qemu_system_shutdown_request(); 5345638d180SAndreas Färber cpu_loop_exit(CPU(s390_env_get_cpu(env))); 5351864b94aSAlexander Graf break; 5361864b94aSAlexander Graf #endif 537defb0e31SAlexander Graf default: 538defb0e31SAlexander Graf /* unknown sigp */ 539defb0e31SAlexander Graf fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code); 5405172b780SDavid Hildenbrand cc = SIGP_CC_NOT_OPERATIONAL; 541defb0e31SAlexander Graf } 542defb0e31SAlexander Graf 543defb0e31SAlexander Graf return cc; 544defb0e31SAlexander Graf } 545defb0e31SAlexander Graf #endif 546ad8a4570SAlexander Graf 547ad8a4570SAlexander Graf #ifndef CONFIG_USER_ONLY 548ad8a4570SAlexander Graf void HELPER(xsch)(CPUS390XState *env, uint64_t r1) 549ad8a4570SAlexander Graf { 550ad8a4570SAlexander Graf S390CPU *cpu = s390_env_get_cpu(env); 551ad8a4570SAlexander Graf ioinst_handle_xsch(cpu, r1); 552ad8a4570SAlexander Graf } 553ad8a4570SAlexander Graf 554ad8a4570SAlexander Graf void HELPER(csch)(CPUS390XState *env, uint64_t r1) 555ad8a4570SAlexander Graf { 556ad8a4570SAlexander Graf S390CPU *cpu = s390_env_get_cpu(env); 557ad8a4570SAlexander Graf ioinst_handle_csch(cpu, r1); 558ad8a4570SAlexander Graf } 559ad8a4570SAlexander Graf 560ad8a4570SAlexander Graf void HELPER(hsch)(CPUS390XState *env, uint64_t r1) 561ad8a4570SAlexander Graf { 562ad8a4570SAlexander Graf S390CPU *cpu = s390_env_get_cpu(env); 563ad8a4570SAlexander Graf ioinst_handle_hsch(cpu, r1); 564ad8a4570SAlexander Graf } 565ad8a4570SAlexander Graf 566ad8a4570SAlexander Graf void HELPER(msch)(CPUS390XState *env, uint64_t r1, uint64_t inst) 567ad8a4570SAlexander Graf { 568ad8a4570SAlexander Graf S390CPU *cpu = s390_env_get_cpu(env); 569ad8a4570SAlexander Graf ioinst_handle_msch(cpu, r1, inst >> 16); 570ad8a4570SAlexander Graf } 571ad8a4570SAlexander Graf 572ad8a4570SAlexander Graf void HELPER(rchp)(CPUS390XState *env, uint64_t r1) 573ad8a4570SAlexander Graf { 574ad8a4570SAlexander Graf S390CPU *cpu = s390_env_get_cpu(env); 575ad8a4570SAlexander Graf ioinst_handle_rchp(cpu, r1); 576ad8a4570SAlexander Graf } 577ad8a4570SAlexander Graf 578ad8a4570SAlexander Graf void HELPER(rsch)(CPUS390XState *env, uint64_t r1) 579ad8a4570SAlexander Graf { 580ad8a4570SAlexander Graf S390CPU *cpu = s390_env_get_cpu(env); 581ad8a4570SAlexander Graf ioinst_handle_rsch(cpu, r1); 582ad8a4570SAlexander Graf } 583ad8a4570SAlexander Graf 584ad8a4570SAlexander Graf void HELPER(ssch)(CPUS390XState *env, uint64_t r1, uint64_t inst) 585ad8a4570SAlexander Graf { 586ad8a4570SAlexander Graf S390CPU *cpu = s390_env_get_cpu(env); 587ad8a4570SAlexander Graf ioinst_handle_ssch(cpu, r1, inst >> 16); 588ad8a4570SAlexander Graf } 589ad8a4570SAlexander Graf 590ad8a4570SAlexander Graf void HELPER(stsch)(CPUS390XState *env, uint64_t r1, uint64_t inst) 591ad8a4570SAlexander Graf { 592ad8a4570SAlexander Graf S390CPU *cpu = s390_env_get_cpu(env); 593ad8a4570SAlexander Graf ioinst_handle_stsch(cpu, r1, inst >> 16); 594ad8a4570SAlexander Graf } 595ad8a4570SAlexander Graf 596ad8a4570SAlexander Graf void HELPER(tsch)(CPUS390XState *env, uint64_t r1, uint64_t inst) 597ad8a4570SAlexander Graf { 598ad8a4570SAlexander Graf S390CPU *cpu = s390_env_get_cpu(env); 599ad8a4570SAlexander Graf ioinst_handle_tsch(cpu, r1, inst >> 16); 600ad8a4570SAlexander Graf } 601ad8a4570SAlexander Graf 602ad8a4570SAlexander Graf void HELPER(chsc)(CPUS390XState *env, uint64_t inst) 603ad8a4570SAlexander Graf { 604ad8a4570SAlexander Graf S390CPU *cpu = s390_env_get_cpu(env); 605ad8a4570SAlexander Graf ioinst_handle_chsc(cpu, inst >> 16); 606ad8a4570SAlexander Graf } 607ad8a4570SAlexander Graf #endif 608777c98c3SAurelien Jarno 609777c98c3SAurelien Jarno #ifndef CONFIG_USER_ONLY 610777c98c3SAurelien Jarno void HELPER(per_check_exception)(CPUS390XState *env) 611777c98c3SAurelien Jarno { 612777c98c3SAurelien Jarno CPUState *cs = CPU(s390_env_get_cpu(env)); 613777c98c3SAurelien Jarno 614777c98c3SAurelien Jarno if (env->per_perc_atmid) { 615777c98c3SAurelien Jarno env->int_pgm_code = PGM_PER; 616777c98c3SAurelien Jarno env->int_pgm_ilen = get_ilen(cpu_ldub_code(env, env->per_address)); 617777c98c3SAurelien Jarno 618777c98c3SAurelien Jarno cs->exception_index = EXCP_PGM; 619777c98c3SAurelien Jarno cpu_loop_exit(cs); 620777c98c3SAurelien Jarno } 621777c98c3SAurelien Jarno } 6222c2275ebSAurelien Jarno 6232c2275ebSAurelien Jarno void HELPER(per_branch)(CPUS390XState *env, uint64_t from, uint64_t to) 6242c2275ebSAurelien Jarno { 6252c2275ebSAurelien Jarno if ((env->cregs[9] & PER_CR9_EVENT_BRANCH)) { 6262c2275ebSAurelien Jarno if (!(env->cregs[9] & PER_CR9_CONTROL_BRANCH_ADDRESS) 6272c2275ebSAurelien Jarno || get_per_in_range(env, to)) { 6282c2275ebSAurelien Jarno env->per_address = from; 6292c2275ebSAurelien Jarno env->per_perc_atmid = PER_CODE_EVENT_BRANCH | get_per_atmid(env); 6302c2275ebSAurelien Jarno } 6312c2275ebSAurelien Jarno } 6322c2275ebSAurelien Jarno } 633f0e0d817SAurelien Jarno 634f0e0d817SAurelien Jarno void HELPER(per_ifetch)(CPUS390XState *env, uint64_t addr) 635f0e0d817SAurelien Jarno { 636f0e0d817SAurelien Jarno if ((env->cregs[9] & PER_CR9_EVENT_IFETCH) && get_per_in_range(env, addr)) { 637f0e0d817SAurelien Jarno env->per_address = addr; 638f0e0d817SAurelien Jarno env->per_perc_atmid = PER_CODE_EVENT_IFETCH | get_per_atmid(env); 63983bb1612SAurelien Jarno 64083bb1612SAurelien Jarno /* If the instruction has to be nullified, trigger the 64183bb1612SAurelien Jarno exception immediately. */ 64283bb1612SAurelien Jarno if (env->cregs[9] & PER_CR9_EVENT_NULLIFICATION) { 64383bb1612SAurelien Jarno CPUState *cs = CPU(s390_env_get_cpu(env)); 64483bb1612SAurelien Jarno 64583bb1612SAurelien Jarno env->int_pgm_code = PGM_PER; 64683bb1612SAurelien Jarno env->int_pgm_ilen = get_ilen(cpu_ldub_code(env, addr)); 64783bb1612SAurelien Jarno 64883bb1612SAurelien Jarno cs->exception_index = EXCP_PGM; 64983bb1612SAurelien Jarno cpu_loop_exit(cs); 65083bb1612SAurelien Jarno } 651f0e0d817SAurelien Jarno } 652f0e0d817SAurelien Jarno } 653777c98c3SAurelien Jarno #endif 654