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" 243208afbeSLluís Vilanova #include "helper.h" 25defb0e31SAlexander Graf #include <string.h> 269c17d615SPaolo Bonzini #include "sysemu/kvm.h" 271de7afc9SPaolo Bonzini #include "qemu/timer.h" 28af2be207SJan Kiszka #ifdef CONFIG_KVM 29af2be207SJan Kiszka #include <linux/kvm.h> 30af2be207SJan Kiszka #endif 3110ec5117SAlexander Graf 321864b94aSAlexander Graf #if !defined(CONFIG_USER_ONLY) 33022c62cbSPaolo Bonzini #include "exec/softmmu_exec.h" 34f0778475SChristian Borntraeger #include "sysemu/cpus.h" 359c17d615SPaolo Bonzini #include "sysemu/sysemu.h" 3610ec5117SAlexander Graf #endif 37d5a43964SAlexander Graf 38defb0e31SAlexander Graf /* #define DEBUG_HELPER */ 39defb0e31SAlexander Graf #ifdef DEBUG_HELPER 40defb0e31SAlexander Graf #define HELPER_LOG(x...) qemu_log(x) 41defb0e31SAlexander Graf #else 42defb0e31SAlexander Graf #define HELPER_LOG(x...) 43defb0e31SAlexander Graf #endif 44defb0e31SAlexander Graf 45b4e2bd35SRichard Henderson /* Raise an exception dynamically from a helper function. */ 46b4e2bd35SRichard Henderson void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp, 47b4e2bd35SRichard Henderson uintptr_t retaddr) 48b4e2bd35SRichard Henderson { 49b4e2bd35SRichard Henderson int t; 50b4e2bd35SRichard Henderson 51b4e2bd35SRichard Henderson env->exception_index = EXCP_PGM; 52b4e2bd35SRichard Henderson env->int_pgm_code = excp; 53b4e2bd35SRichard Henderson 54b4e2bd35SRichard Henderson /* Use the (ultimate) callers address to find the insn that trapped. */ 55b4e2bd35SRichard Henderson cpu_restore_state(env, retaddr); 56b4e2bd35SRichard Henderson 57b4e2bd35SRichard Henderson /* Advance past the insn. */ 58b4e2bd35SRichard Henderson t = cpu_ldub_code(env, env->psw.addr); 59b4e2bd35SRichard Henderson env->int_pgm_ilen = t = get_ilen(t); 60b4e2bd35SRichard Henderson env->psw.addr += 2 * t; 61b4e2bd35SRichard Henderson 62b4e2bd35SRichard Henderson cpu_loop_exit(env); 63b4e2bd35SRichard Henderson } 64b4e2bd35SRichard Henderson 65d5a103cdSRichard Henderson /* Raise an exception statically from a TB. */ 66089f5c06SBlue Swirl void HELPER(exception)(CPUS390XState *env, uint32_t excp) 67defb0e31SAlexander Graf { 6871e47088SBlue Swirl HELPER_LOG("%s: exception %d\n", __func__, excp); 69defb0e31SAlexander Graf env->exception_index = excp; 701162c041SBlue Swirl cpu_loop_exit(env); 71defb0e31SAlexander Graf } 72defb0e31SAlexander Graf 73defb0e31SAlexander Graf #ifndef CONFIG_USER_ONLY 74a158986dSStefan Weil 75a158986dSStefan Weil /* EBCDIC handling */ 76a158986dSStefan Weil static const uint8_t ebcdic2ascii[] = { 77a158986dSStefan Weil 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F, 78a158986dSStefan Weil 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 79a158986dSStefan Weil 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07, 80a158986dSStefan Weil 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 81a158986dSStefan Weil 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B, 82a158986dSStefan Weil 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07, 83a158986dSStefan Weil 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04, 84a158986dSStefan Weil 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A, 85a158986dSStefan Weil 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86, 86a158986dSStefan Weil 0x87, 0xA4, 0x5B, 0x2E, 0x3C, 0x28, 0x2B, 0x21, 87a158986dSStefan Weil 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07, 88a158986dSStefan Weil 0x8D, 0xE1, 0x5D, 0x24, 0x2A, 0x29, 0x3B, 0x5E, 89a158986dSStefan Weil 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F, 90a158986dSStefan Weil 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, 91a158986dSStefan Weil 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 92a158986dSStefan Weil 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, 93a158986dSStefan Weil 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 94a158986dSStefan Weil 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1, 95a158986dSStefan Weil 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 96a158986dSStefan Weil 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07, 97a158986dSStefan Weil 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 98a158986dSStefan Weil 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07, 99a158986dSStefan Weil 0x9B, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC, 100a158986dSStefan Weil 0xAB, 0x07, 0xAA, 0x7C, 0x07, 0x07, 0x07, 0x07, 101a158986dSStefan Weil 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 102a158986dSStefan Weil 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07, 103a158986dSStefan Weil 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 104a158986dSStefan Weil 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98, 105a158986dSStefan Weil 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 106a158986dSStefan Weil 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07, 107a158986dSStefan Weil 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 108a158986dSStefan Weil 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07, 109a158986dSStefan Weil }; 110a158986dSStefan Weil 111a158986dSStefan Weil static const uint8_t ascii2ebcdic[] = { 112a158986dSStefan Weil 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, 113a158986dSStefan Weil 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 114a158986dSStefan Weil 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26, 115a158986dSStefan Weil 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F, 116a158986dSStefan Weil 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, 117a158986dSStefan Weil 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, 118a158986dSStefan Weil 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 119a158986dSStefan Weil 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, 120a158986dSStefan Weil 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 121a158986dSStefan Weil 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 122a158986dSStefan Weil 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 123a158986dSStefan Weil 0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D, 124a158986dSStefan Weil 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 125a158986dSStefan Weil 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 126a158986dSStefan Weil 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 127a158986dSStefan Weil 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07, 128a158986dSStefan Weil 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 129a158986dSStefan Weil 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 130a158986dSStefan Weil 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 131a158986dSStefan Weil 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 132a158986dSStefan Weil 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 133a158986dSStefan Weil 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 134a158986dSStefan Weil 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 135a158986dSStefan Weil 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 136a158986dSStefan Weil 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 137a158986dSStefan Weil 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 138a158986dSStefan Weil 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 139a158986dSStefan Weil 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 140a158986dSStefan Weil 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 141a158986dSStefan Weil 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 142a158986dSStefan Weil 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 143a158986dSStefan Weil 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF 144a158986dSStefan Weil }; 145a158986dSStefan Weil 146a158986dSStefan Weil static inline void ebcdic_put(uint8_t *p, const char *ascii, int len) 147a158986dSStefan Weil { 148a158986dSStefan Weil int i; 149a158986dSStefan Weil 150a158986dSStefan Weil for (i = 0; i < len; i++) { 151a158986dSStefan Weil p[i] = ascii2ebcdic[(uint8_t)ascii[i]]; 152a158986dSStefan Weil } 153a158986dSStefan Weil } 154a158986dSStefan Weil 155d5a103cdSRichard Henderson void program_interrupt(CPUS390XState *env, uint32_t code, int ilen) 156defb0e31SAlexander Graf { 1570d404541SRichard Henderson qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n", 1580d404541SRichard Henderson env->psw.addr); 159defb0e31SAlexander Graf 160defb0e31SAlexander Graf if (kvm_enabled()) { 161af2be207SJan Kiszka #ifdef CONFIG_KVM 1621bc22652SAndreas Färber kvm_s390_interrupt(s390_env_get_cpu(env), KVM_S390_PROGRAM_INT, code); 163af2be207SJan Kiszka #endif 164defb0e31SAlexander Graf } else { 165defb0e31SAlexander Graf env->int_pgm_code = code; 166d5a103cdSRichard Henderson env->int_pgm_ilen = ilen; 167defb0e31SAlexander Graf env->exception_index = EXCP_PGM; 1681162c041SBlue Swirl cpu_loop_exit(env); 169defb0e31SAlexander Graf } 170defb0e31SAlexander Graf } 171defb0e31SAlexander Graf 172defb0e31SAlexander Graf /* SCLP service call */ 173dc458df9SRichard Henderson uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2) 174defb0e31SAlexander Graf { 175dc458df9SRichard Henderson int r = sclp_service_call(r1, r2); 1769abf567dSChristian Borntraeger if (r < 0) { 1779abf567dSChristian Borntraeger program_interrupt(env, -r, 4); 178d5a43964SAlexander Graf return 0; 179d5a43964SAlexander Graf } 1809abf567dSChristian Borntraeger return r; 1819abf567dSChristian Borntraeger } 182defb0e31SAlexander Graf 183268846baSEugene (jno) Dvurechenski #ifndef CONFIG_USER_ONLY 184f0778475SChristian Borntraeger static void cpu_reset_all(void) 185f0778475SChristian Borntraeger { 186bdc44640SAndreas Färber CPUState *cs; 187f0778475SChristian Borntraeger S390CPUClass *scc; 188f0778475SChristian Borntraeger 189bdc44640SAndreas Färber CPU_FOREACH(cs) { 190bdc44640SAndreas Färber scc = S390_CPU_GET_CLASS(cs); 191bdc44640SAndreas Färber scc->cpu_reset(cs); 192f0778475SChristian Borntraeger } 193f0778475SChristian Borntraeger } 194f0778475SChristian Borntraeger 195d8b30c83SChristian Borntraeger static void cpu_full_reset_all(void) 196d8b30c83SChristian Borntraeger { 197d8b30c83SChristian Borntraeger CPUState *cpu; 198d8b30c83SChristian Borntraeger 199d8b30c83SChristian Borntraeger CPU_FOREACH(cpu) { 200d8b30c83SChristian Borntraeger cpu_reset(cpu); 201d8b30c83SChristian Borntraeger } 202d8b30c83SChristian Borntraeger } 203d8b30c83SChristian Borntraeger 204d8b30c83SChristian Borntraeger static int modified_clear_reset(S390CPU *cpu) 205d8b30c83SChristian Borntraeger { 206d8b30c83SChristian Borntraeger S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); 207d8b30c83SChristian Borntraeger 208d8b30c83SChristian Borntraeger pause_all_vcpus(); 209d8b30c83SChristian Borntraeger cpu_synchronize_all_states(); 210d8b30c83SChristian Borntraeger cpu_full_reset_all(); 211d8b30c83SChristian Borntraeger io_subsystem_reset(); 212d8b30c83SChristian Borntraeger scc->load_normal(CPU(cpu)); 213d8b30c83SChristian Borntraeger cpu_synchronize_all_post_reset(); 214d8b30c83SChristian Borntraeger resume_all_vcpus(); 215d8b30c83SChristian Borntraeger return 0; 216d8b30c83SChristian Borntraeger } 217d8b30c83SChristian Borntraeger 218f0778475SChristian Borntraeger static int load_normal_reset(S390CPU *cpu) 219f0778475SChristian Borntraeger { 220f0778475SChristian Borntraeger S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); 221f0778475SChristian Borntraeger 222f0778475SChristian Borntraeger pause_all_vcpus(); 223f0778475SChristian Borntraeger cpu_synchronize_all_states(); 224f0778475SChristian Borntraeger cpu_reset_all(); 225f0778475SChristian Borntraeger io_subsystem_reset(); 226f0778475SChristian Borntraeger scc->initial_cpu_reset(CPU(cpu)); 227f0778475SChristian Borntraeger scc->load_normal(CPU(cpu)); 228f0778475SChristian Borntraeger cpu_synchronize_all_post_reset(); 229f0778475SChristian Borntraeger resume_all_vcpus(); 230f0778475SChristian Borntraeger return 0; 231f0778475SChristian Borntraeger } 232f0778475SChristian Borntraeger 233268846baSEugene (jno) Dvurechenski #define DIAG_308_RC_NO_CONF 0x0102 234268846baSEugene (jno) Dvurechenski #define DIAG_308_RC_INVALID 0x0402 235268846baSEugene (jno) Dvurechenski void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3) 236268846baSEugene (jno) Dvurechenski { 237268846baSEugene (jno) Dvurechenski uint64_t addr = env->regs[r1]; 238268846baSEugene (jno) Dvurechenski uint64_t subcode = env->regs[r3]; 239268846baSEugene (jno) Dvurechenski 240268846baSEugene (jno) Dvurechenski if (env->psw.mask & PSW_MASK_PSTATE) { 241268846baSEugene (jno) Dvurechenski program_interrupt(env, PGM_PRIVILEGED, ILEN_LATER_INC); 242268846baSEugene (jno) Dvurechenski return; 243268846baSEugene (jno) Dvurechenski } 244268846baSEugene (jno) Dvurechenski 245268846baSEugene (jno) Dvurechenski if ((subcode & ~0x0ffffULL) || (subcode > 6)) { 246268846baSEugene (jno) Dvurechenski program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC); 247268846baSEugene (jno) Dvurechenski return; 248268846baSEugene (jno) Dvurechenski } 249268846baSEugene (jno) Dvurechenski 250268846baSEugene (jno) Dvurechenski switch (subcode) { 251d8b30c83SChristian Borntraeger case 0: 252d8b30c83SChristian Borntraeger modified_clear_reset(s390_env_get_cpu(env)); 253d8b30c83SChristian Borntraeger break; 254f0778475SChristian Borntraeger case 1: 255f0778475SChristian Borntraeger load_normal_reset(s390_env_get_cpu(env)); 256f0778475SChristian Borntraeger break; 257268846baSEugene (jno) Dvurechenski case 5: 258268846baSEugene (jno) Dvurechenski if ((r1 & 1) || (addr & 0x0fffULL)) { 259268846baSEugene (jno) Dvurechenski program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC); 260268846baSEugene (jno) Dvurechenski return; 261268846baSEugene (jno) Dvurechenski } 262268846baSEugene (jno) Dvurechenski env->regs[r1+1] = DIAG_308_RC_INVALID; 263268846baSEugene (jno) Dvurechenski return; 264268846baSEugene (jno) Dvurechenski case 6: 265268846baSEugene (jno) Dvurechenski if ((r1 & 1) || (addr & 0x0fffULL)) { 266268846baSEugene (jno) Dvurechenski program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC); 267268846baSEugene (jno) Dvurechenski return; 268268846baSEugene (jno) Dvurechenski } 269268846baSEugene (jno) Dvurechenski env->regs[r1+1] = DIAG_308_RC_NO_CONF; 270268846baSEugene (jno) Dvurechenski return; 271268846baSEugene (jno) Dvurechenski default: 272268846baSEugene (jno) Dvurechenski hw_error("Unhandled diag308 subcode %" PRIx64, subcode); 273268846baSEugene (jno) Dvurechenski break; 274268846baSEugene (jno) Dvurechenski } 275268846baSEugene (jno) Dvurechenski } 276268846baSEugene (jno) Dvurechenski #endif 277268846baSEugene (jno) Dvurechenski 278defb0e31SAlexander Graf /* DIAG */ 279089f5c06SBlue Swirl uint64_t HELPER(diag)(CPUS390XState *env, uint32_t num, uint64_t mem, 280089f5c06SBlue Swirl uint64_t code) 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 */ 295defb0e31SAlexander Graf r = 0; 296defb0e31SAlexander Graf break; 297defb0e31SAlexander Graf default: 298defb0e31SAlexander Graf r = -1; 299defb0e31SAlexander Graf break; 300defb0e31SAlexander Graf } 301defb0e31SAlexander Graf 302defb0e31SAlexander Graf if (r) { 303d5a103cdSRichard Henderson program_interrupt(env, PGM_OPERATION, ILEN_LATER_INC); 304defb0e31SAlexander Graf } 305defb0e31SAlexander Graf 306defb0e31SAlexander Graf return r; 307defb0e31SAlexander Graf } 308defb0e31SAlexander Graf 309defb0e31SAlexander Graf /* Set Prefix */ 310089f5c06SBlue Swirl void HELPER(spx)(CPUS390XState *env, uint64_t a1) 311defb0e31SAlexander Graf { 312e805a0d3SRichard Henderson uint32_t prefix = a1 & 0x7fffe000; 313e805a0d3SRichard Henderson env->psa = prefix; 314defb0e31SAlexander Graf qemu_log("prefix: %#x\n", prefix); 315defb0e31SAlexander Graf tlb_flush_page(env, 0); 316defb0e31SAlexander Graf tlb_flush_page(env, TARGET_PAGE_SIZE); 317defb0e31SAlexander Graf } 318defb0e31SAlexander Graf 319a4e3ad19SAndreas Färber static inline uint64_t clock_value(CPUS390XState *env) 320defb0e31SAlexander Graf { 321defb0e31SAlexander Graf uint64_t time; 322defb0e31SAlexander Graf 323defb0e31SAlexander Graf time = env->tod_offset + 324bc72ad67SAlex Bligh time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - env->tod_basetime); 325defb0e31SAlexander Graf 326defb0e31SAlexander Graf return time; 327defb0e31SAlexander Graf } 328defb0e31SAlexander Graf 329defb0e31SAlexander Graf /* Store Clock */ 330434c91a5SRichard Henderson uint64_t HELPER(stck)(CPUS390XState *env) 331defb0e31SAlexander Graf { 332434c91a5SRichard Henderson return clock_value(env); 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 342defb0e31SAlexander Graf /* difference between now and then */ 343defb0e31SAlexander Graf time -= clock_value(env); 344defb0e31SAlexander Graf /* nanoseconds */ 345defb0e31SAlexander Graf time = (time * 125) >> 9; 346defb0e31SAlexander Graf 347bc72ad67SAlex Bligh timer_mod(env->tod_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time); 348defb0e31SAlexander Graf } 349defb0e31SAlexander Graf 350defb0e31SAlexander Graf /* Store Clock Comparator */ 351dd3eb7b5SRichard Henderson uint64_t HELPER(stckc)(CPUS390XState *env) 352defb0e31SAlexander Graf { 353defb0e31SAlexander Graf /* XXX implement */ 354dd3eb7b5SRichard Henderson return 0; 355defb0e31SAlexander Graf } 356defb0e31SAlexander Graf 357defb0e31SAlexander Graf /* Set CPU Timer */ 358c4f0a863SRichard Henderson void HELPER(spt)(CPUS390XState *env, uint64_t time) 359defb0e31SAlexander Graf { 360defb0e31SAlexander Graf if (time == -1ULL) { 361defb0e31SAlexander Graf return; 362defb0e31SAlexander Graf } 363defb0e31SAlexander Graf 364defb0e31SAlexander Graf /* nanoseconds */ 365defb0e31SAlexander Graf time = (time * 125) >> 9; 366defb0e31SAlexander Graf 367bc72ad67SAlex Bligh timer_mod(env->cpu_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time); 368defb0e31SAlexander Graf } 369defb0e31SAlexander Graf 370defb0e31SAlexander Graf /* Store CPU Timer */ 371c4f0a863SRichard Henderson uint64_t HELPER(stpt)(CPUS390XState *env) 372defb0e31SAlexander Graf { 373defb0e31SAlexander Graf /* XXX implement */ 374c4f0a863SRichard Henderson return 0; 375defb0e31SAlexander Graf } 376defb0e31SAlexander Graf 377defb0e31SAlexander Graf /* Store System Information */ 378d14b3e09SRichard Henderson uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, 379d14b3e09SRichard Henderson uint64_t r0, uint64_t r1) 380defb0e31SAlexander Graf { 381defb0e31SAlexander Graf int cc = 0; 382defb0e31SAlexander Graf int sel1, sel2; 383defb0e31SAlexander Graf 384defb0e31SAlexander Graf if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 && 385defb0e31SAlexander Graf ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) { 386defb0e31SAlexander Graf /* valid function code, invalid reserved bits */ 387defb0e31SAlexander Graf program_interrupt(env, PGM_SPECIFICATION, 2); 388defb0e31SAlexander Graf } 389defb0e31SAlexander Graf 390defb0e31SAlexander Graf sel1 = r0 & STSI_R0_SEL1_MASK; 391defb0e31SAlexander Graf sel2 = r1 & STSI_R1_SEL2_MASK; 392defb0e31SAlexander Graf 393defb0e31SAlexander Graf /* XXX: spec exception if sysib is not 4k-aligned */ 394defb0e31SAlexander Graf 395defb0e31SAlexander Graf switch (r0 & STSI_LEVEL_MASK) { 396defb0e31SAlexander Graf case STSI_LEVEL_1: 397defb0e31SAlexander Graf if ((sel1 == 1) && (sel2 == 1)) { 398defb0e31SAlexander Graf /* Basic Machine Configuration */ 399defb0e31SAlexander Graf struct sysib_111 sysib; 400defb0e31SAlexander Graf 401defb0e31SAlexander Graf memset(&sysib, 0, sizeof(sysib)); 402defb0e31SAlexander Graf ebcdic_put(sysib.manuf, "QEMU ", 16); 403defb0e31SAlexander Graf /* same as machine type number in STORE CPU ID */ 404defb0e31SAlexander Graf ebcdic_put(sysib.type, "QEMU", 4); 405defb0e31SAlexander Graf /* same as model number in STORE CPU ID */ 406defb0e31SAlexander Graf ebcdic_put(sysib.model, "QEMU ", 16); 407defb0e31SAlexander Graf ebcdic_put(sysib.sequence, "QEMU ", 16); 408defb0e31SAlexander Graf ebcdic_put(sysib.plant, "QEMU", 4); 409defb0e31SAlexander Graf cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); 410defb0e31SAlexander Graf } else if ((sel1 == 2) && (sel2 == 1)) { 411defb0e31SAlexander Graf /* Basic Machine CPU */ 412defb0e31SAlexander Graf struct sysib_121 sysib; 413defb0e31SAlexander Graf 414defb0e31SAlexander Graf memset(&sysib, 0, sizeof(sysib)); 415defb0e31SAlexander Graf /* XXX make different for different CPUs? */ 416defb0e31SAlexander Graf ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16); 417defb0e31SAlexander Graf ebcdic_put(sysib.plant, "QEMU", 4); 418defb0e31SAlexander Graf stw_p(&sysib.cpu_addr, env->cpu_num); 419defb0e31SAlexander Graf cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); 420defb0e31SAlexander Graf } else if ((sel1 == 2) && (sel2 == 2)) { 421defb0e31SAlexander Graf /* Basic Machine CPUs */ 422defb0e31SAlexander Graf struct sysib_122 sysib; 423defb0e31SAlexander Graf 424defb0e31SAlexander Graf memset(&sysib, 0, sizeof(sysib)); 425defb0e31SAlexander Graf stl_p(&sysib.capability, 0x443afc29); 426defb0e31SAlexander Graf /* XXX change when SMP comes */ 427defb0e31SAlexander Graf stw_p(&sysib.total_cpus, 1); 428defb0e31SAlexander Graf stw_p(&sysib.active_cpus, 1); 429defb0e31SAlexander Graf stw_p(&sysib.standby_cpus, 0); 430defb0e31SAlexander Graf stw_p(&sysib.reserved_cpus, 0); 431defb0e31SAlexander Graf cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); 432defb0e31SAlexander Graf } else { 433defb0e31SAlexander Graf cc = 3; 434defb0e31SAlexander Graf } 435defb0e31SAlexander Graf break; 436defb0e31SAlexander Graf case STSI_LEVEL_2: 437defb0e31SAlexander Graf { 438defb0e31SAlexander Graf if ((sel1 == 2) && (sel2 == 1)) { 439defb0e31SAlexander Graf /* LPAR CPU */ 440defb0e31SAlexander Graf struct sysib_221 sysib; 441defb0e31SAlexander Graf 442defb0e31SAlexander Graf memset(&sysib, 0, sizeof(sysib)); 443defb0e31SAlexander Graf /* XXX make different for different CPUs? */ 444defb0e31SAlexander Graf ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16); 445defb0e31SAlexander Graf ebcdic_put(sysib.plant, "QEMU", 4); 446defb0e31SAlexander Graf stw_p(&sysib.cpu_addr, env->cpu_num); 447defb0e31SAlexander Graf stw_p(&sysib.cpu_id, 0); 448defb0e31SAlexander Graf cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); 449defb0e31SAlexander Graf } else if ((sel1 == 2) && (sel2 == 2)) { 450defb0e31SAlexander Graf /* LPAR CPUs */ 451defb0e31SAlexander Graf struct sysib_222 sysib; 452defb0e31SAlexander Graf 453defb0e31SAlexander Graf memset(&sysib, 0, sizeof(sysib)); 454defb0e31SAlexander Graf stw_p(&sysib.lpar_num, 0); 455defb0e31SAlexander Graf sysib.lcpuc = 0; 456defb0e31SAlexander Graf /* XXX change when SMP comes */ 457defb0e31SAlexander Graf stw_p(&sysib.total_cpus, 1); 458defb0e31SAlexander Graf stw_p(&sysib.conf_cpus, 1); 459defb0e31SAlexander Graf stw_p(&sysib.standby_cpus, 0); 460defb0e31SAlexander Graf stw_p(&sysib.reserved_cpus, 0); 461defb0e31SAlexander Graf ebcdic_put(sysib.name, "QEMU ", 8); 462defb0e31SAlexander Graf stl_p(&sysib.caf, 1000); 463defb0e31SAlexander Graf stw_p(&sysib.dedicated_cpus, 0); 464defb0e31SAlexander Graf stw_p(&sysib.shared_cpus, 0); 465defb0e31SAlexander Graf cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); 466defb0e31SAlexander Graf } else { 467defb0e31SAlexander Graf cc = 3; 468defb0e31SAlexander Graf } 469defb0e31SAlexander Graf break; 470defb0e31SAlexander Graf } 471defb0e31SAlexander Graf case STSI_LEVEL_3: 472defb0e31SAlexander Graf { 473defb0e31SAlexander Graf if ((sel1 == 2) && (sel2 == 2)) { 474defb0e31SAlexander Graf /* VM CPUs */ 475defb0e31SAlexander Graf struct sysib_322 sysib; 476defb0e31SAlexander Graf 477defb0e31SAlexander Graf memset(&sysib, 0, sizeof(sysib)); 478defb0e31SAlexander Graf sysib.count = 1; 479defb0e31SAlexander Graf /* XXX change when SMP comes */ 480defb0e31SAlexander Graf stw_p(&sysib.vm[0].total_cpus, 1); 481defb0e31SAlexander Graf stw_p(&sysib.vm[0].conf_cpus, 1); 482defb0e31SAlexander Graf stw_p(&sysib.vm[0].standby_cpus, 0); 483defb0e31SAlexander Graf stw_p(&sysib.vm[0].reserved_cpus, 0); 484defb0e31SAlexander Graf ebcdic_put(sysib.vm[0].name, "KVMguest", 8); 485defb0e31SAlexander Graf stl_p(&sysib.vm[0].caf, 1000); 486defb0e31SAlexander Graf ebcdic_put(sysib.vm[0].cpi, "KVM/Linux ", 16); 487defb0e31SAlexander Graf cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); 488defb0e31SAlexander Graf } else { 489defb0e31SAlexander Graf cc = 3; 490defb0e31SAlexander Graf } 491defb0e31SAlexander Graf break; 492defb0e31SAlexander Graf } 493defb0e31SAlexander Graf case STSI_LEVEL_CURRENT: 494defb0e31SAlexander Graf env->regs[0] = STSI_LEVEL_3; 495defb0e31SAlexander Graf break; 496defb0e31SAlexander Graf default: 497defb0e31SAlexander Graf cc = 3; 498defb0e31SAlexander Graf break; 499defb0e31SAlexander Graf } 500defb0e31SAlexander Graf 501defb0e31SAlexander Graf return cc; 502defb0e31SAlexander Graf } 503defb0e31SAlexander Graf 504089f5c06SBlue Swirl uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1, 505089f5c06SBlue Swirl uint64_t cpu_addr) 506defb0e31SAlexander Graf { 507defb0e31SAlexander Graf int cc = 0; 508defb0e31SAlexander Graf 509defb0e31SAlexander Graf HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n", 51071e47088SBlue Swirl __func__, order_code, r1, cpu_addr); 511defb0e31SAlexander Graf 512defb0e31SAlexander Graf /* Remember: Use "R1 or R1 + 1, whichever is the odd-numbered register" 513defb0e31SAlexander Graf as parameter (input). Status (output) is always R1. */ 514defb0e31SAlexander Graf 515defb0e31SAlexander Graf switch (order_code) { 516defb0e31SAlexander Graf case SIGP_SET_ARCH: 517defb0e31SAlexander Graf /* switch arch */ 518defb0e31SAlexander Graf break; 519defb0e31SAlexander Graf case SIGP_SENSE: 520defb0e31SAlexander Graf /* enumerate CPU status */ 521defb0e31SAlexander Graf if (cpu_addr) { 522defb0e31SAlexander Graf /* XXX implement when SMP comes */ 523defb0e31SAlexander Graf return 3; 524defb0e31SAlexander Graf } 525defb0e31SAlexander Graf env->regs[r1] &= 0xffffffff00000000ULL; 526defb0e31SAlexander Graf cc = 1; 527defb0e31SAlexander Graf break; 5281864b94aSAlexander Graf #if !defined(CONFIG_USER_ONLY) 5291864b94aSAlexander Graf case SIGP_RESTART: 5301864b94aSAlexander Graf qemu_system_reset_request(); 5311864b94aSAlexander Graf cpu_loop_exit(env); 5321864b94aSAlexander Graf break; 5331864b94aSAlexander Graf case SIGP_STOP: 5341864b94aSAlexander Graf qemu_system_shutdown_request(); 5351864b94aSAlexander Graf cpu_loop_exit(env); 5361864b94aSAlexander Graf break; 5371864b94aSAlexander Graf #endif 538defb0e31SAlexander Graf default: 539defb0e31SAlexander Graf /* unknown sigp */ 540defb0e31SAlexander Graf fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code); 541defb0e31SAlexander Graf cc = 3; 542defb0e31SAlexander Graf } 543defb0e31SAlexander Graf 544defb0e31SAlexander Graf return cc; 545defb0e31SAlexander Graf } 546defb0e31SAlexander Graf #endif 547