1000a1a38SChristian Borntraeger /* 2000a1a38SChristian Borntraeger * QEMU S/390 Interrupt support 3000a1a38SChristian Borntraeger * 479afc36dSCornelia Huck * Copyright IBM Corp. 2012, 2014 5000a1a38SChristian Borntraeger * 6000a1a38SChristian Borntraeger * This work is licensed under the terms of the GNU GPL, version 2 or (at your 7000a1a38SChristian Borntraeger * option) any later version. See the COPYING file in the top-level directory. 8000a1a38SChristian Borntraeger */ 9000a1a38SChristian Borntraeger 109615495aSPeter Maydell #include "qemu/osdep.h" 11e3cfd926SThomas Huth #include "qemu/log.h" 12000a1a38SChristian Borntraeger #include "cpu.h" 13*f16bbb9bSDavid Hildenbrand #include "kvm_s390x.h" 144e58b838SDavid Hildenbrand #include "internal.h" 15e3cfd926SThomas Huth #include "exec/exec-all.h" 169c17d615SPaolo Bonzini #include "sysemu/kvm.h" 17bd3f16acSPaolo Bonzini #include "hw/s390x/ioinst.h" 18bd3f16acSPaolo Bonzini 19e3cfd926SThomas Huth /* Ensure to exit the TB after this call! */ 20e3cfd926SThomas Huth void trigger_pgm_exception(CPUS390XState *env, uint32_t code, uint32_t ilen) 21e3cfd926SThomas Huth { 22e3cfd926SThomas Huth CPUState *cs = CPU(s390_env_get_cpu(env)); 23e3cfd926SThomas Huth 24e3cfd926SThomas Huth cs->exception_index = EXCP_PGM; 25e3cfd926SThomas Huth env->int_pgm_code = code; 26e3cfd926SThomas Huth env->int_pgm_ilen = ilen; 27e3cfd926SThomas Huth } 28e3cfd926SThomas Huth 29e3cfd926SThomas Huth static void tcg_s390_program_interrupt(CPUS390XState *env, uint32_t code, 30e3cfd926SThomas Huth int ilen) 31e3cfd926SThomas Huth { 32e3cfd926SThomas Huth #ifdef CONFIG_TCG 33e3cfd926SThomas Huth trigger_pgm_exception(env, code, ilen); 34e3cfd926SThomas Huth cpu_loop_exit(CPU(s390_env_get_cpu(env))); 35e3cfd926SThomas Huth #else 36e3cfd926SThomas Huth g_assert_not_reached(); 37e3cfd926SThomas Huth #endif 38e3cfd926SThomas Huth } 39e3cfd926SThomas Huth 40e3cfd926SThomas Huth void program_interrupt(CPUS390XState *env, uint32_t code, int ilen) 41e3cfd926SThomas Huth { 42e3cfd926SThomas Huth S390CPU *cpu = s390_env_get_cpu(env); 43e3cfd926SThomas Huth 44e3cfd926SThomas Huth qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n", 45e3cfd926SThomas Huth env->psw.addr); 46e3cfd926SThomas Huth 47e3cfd926SThomas Huth if (kvm_enabled()) { 48e3cfd926SThomas Huth kvm_s390_program_interrupt(cpu, code); 49e3cfd926SThomas Huth } else if (tcg_enabled()) { 50e3cfd926SThomas Huth tcg_s390_program_interrupt(env, code, ilen); 51e3cfd926SThomas Huth } else { 52e3cfd926SThomas Huth g_assert_not_reached(); 53e3cfd926SThomas Huth } 54e3cfd926SThomas Huth } 55e3cfd926SThomas Huth 56bd3f16acSPaolo Bonzini #if !defined(CONFIG_USER_ONLY) 57bd3f16acSPaolo Bonzini void cpu_inject_ext(S390CPU *cpu, uint32_t code, uint32_t param, 58bd3f16acSPaolo Bonzini uint64_t param64) 59bd3f16acSPaolo Bonzini { 60bd3f16acSPaolo Bonzini CPUS390XState *env = &cpu->env; 61bd3f16acSPaolo Bonzini 62bd3f16acSPaolo Bonzini if (env->ext_index == MAX_EXT_QUEUE - 1) { 63bd3f16acSPaolo Bonzini /* ugh - can't queue anymore. Let's drop. */ 64bd3f16acSPaolo Bonzini return; 65bd3f16acSPaolo Bonzini } 66bd3f16acSPaolo Bonzini 67bd3f16acSPaolo Bonzini env->ext_index++; 68bd3f16acSPaolo Bonzini assert(env->ext_index < MAX_EXT_QUEUE); 69bd3f16acSPaolo Bonzini 70bd3f16acSPaolo Bonzini env->ext_queue[env->ext_index].code = code; 71bd3f16acSPaolo Bonzini env->ext_queue[env->ext_index].param = param; 72bd3f16acSPaolo Bonzini env->ext_queue[env->ext_index].param64 = param64; 73bd3f16acSPaolo Bonzini 74bd3f16acSPaolo Bonzini env->pending_int |= INTERRUPT_EXT; 75bd3f16acSPaolo Bonzini cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 76bd3f16acSPaolo Bonzini } 77bd3f16acSPaolo Bonzini 78bd3f16acSPaolo Bonzini static void cpu_inject_io(S390CPU *cpu, uint16_t subchannel_id, 79bd3f16acSPaolo Bonzini uint16_t subchannel_number, 80bd3f16acSPaolo Bonzini uint32_t io_int_parm, uint32_t io_int_word) 81bd3f16acSPaolo Bonzini { 82bd3f16acSPaolo Bonzini CPUS390XState *env = &cpu->env; 83bd3f16acSPaolo Bonzini int isc = IO_INT_WORD_ISC(io_int_word); 84bd3f16acSPaolo Bonzini 85bd3f16acSPaolo Bonzini if (env->io_index[isc] == MAX_IO_QUEUE - 1) { 86bd3f16acSPaolo Bonzini /* ugh - can't queue anymore. Let's drop. */ 87bd3f16acSPaolo Bonzini return; 88bd3f16acSPaolo Bonzini } 89bd3f16acSPaolo Bonzini 90bd3f16acSPaolo Bonzini env->io_index[isc]++; 91bd3f16acSPaolo Bonzini assert(env->io_index[isc] < MAX_IO_QUEUE); 92bd3f16acSPaolo Bonzini 93bd3f16acSPaolo Bonzini env->io_queue[env->io_index[isc]][isc].id = subchannel_id; 94bd3f16acSPaolo Bonzini env->io_queue[env->io_index[isc]][isc].nr = subchannel_number; 95bd3f16acSPaolo Bonzini env->io_queue[env->io_index[isc]][isc].parm = io_int_parm; 96bd3f16acSPaolo Bonzini env->io_queue[env->io_index[isc]][isc].word = io_int_word; 97bd3f16acSPaolo Bonzini 98bd3f16acSPaolo Bonzini env->pending_int |= INTERRUPT_IO; 99bd3f16acSPaolo Bonzini cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 100bd3f16acSPaolo Bonzini } 101bd3f16acSPaolo Bonzini 102bd3f16acSPaolo Bonzini static void cpu_inject_crw_mchk(S390CPU *cpu) 103bd3f16acSPaolo Bonzini { 104bd3f16acSPaolo Bonzini CPUS390XState *env = &cpu->env; 105bd3f16acSPaolo Bonzini 106bd3f16acSPaolo Bonzini if (env->mchk_index == MAX_MCHK_QUEUE - 1) { 107bd3f16acSPaolo Bonzini /* ugh - can't queue anymore. Let's drop. */ 108bd3f16acSPaolo Bonzini return; 109bd3f16acSPaolo Bonzini } 110bd3f16acSPaolo Bonzini 111bd3f16acSPaolo Bonzini env->mchk_index++; 112bd3f16acSPaolo Bonzini assert(env->mchk_index < MAX_MCHK_QUEUE); 113bd3f16acSPaolo Bonzini 114bd3f16acSPaolo Bonzini env->mchk_queue[env->mchk_index].type = 1; 115bd3f16acSPaolo Bonzini 116bd3f16acSPaolo Bonzini env->pending_int |= INTERRUPT_MCHK; 117bd3f16acSPaolo Bonzini cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 118bd3f16acSPaolo Bonzini } 119000a1a38SChristian Borntraeger 12079afc36dSCornelia Huck /* 12179afc36dSCornelia Huck * All of the following interrupts are floating, i.e. not per-vcpu. 122de13d216SCornelia Huck * We just need a dummy cpustate in order to be able to inject in the 123de13d216SCornelia Huck * non-kvm case. 12479afc36dSCornelia Huck */ 125000a1a38SChristian Borntraeger void s390_sclp_extint(uint32_t parm) 126000a1a38SChristian Borntraeger { 127de13d216SCornelia Huck if (kvm_enabled()) { 128de13d216SCornelia Huck kvm_s390_service_interrupt(parm); 129de13d216SCornelia Huck } else { 130000a1a38SChristian Borntraeger S390CPU *dummy_cpu = s390_cpu_addr2state(0); 131000a1a38SChristian Borntraeger 132f9466733SAndreas Färber cpu_inject_ext(dummy_cpu, EXT_SERVICE, parm, 0); 133000a1a38SChristian Borntraeger } 134000a1a38SChristian Borntraeger } 13579afc36dSCornelia Huck 136de13d216SCornelia Huck void s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr, 137de13d216SCornelia Huck uint32_t io_int_parm, uint32_t io_int_word) 13879afc36dSCornelia Huck { 13979afc36dSCornelia Huck if (kvm_enabled()) { 140de13d216SCornelia Huck kvm_s390_io_interrupt(subchannel_id, subchannel_nr, io_int_parm, 14179afc36dSCornelia Huck io_int_word); 14279afc36dSCornelia Huck } else { 143de13d216SCornelia Huck S390CPU *dummy_cpu = s390_cpu_addr2state(0); 144de13d216SCornelia Huck 145de13d216SCornelia Huck cpu_inject_io(dummy_cpu, subchannel_id, subchannel_nr, io_int_parm, 14679afc36dSCornelia Huck io_int_word); 14779afc36dSCornelia Huck } 14879afc36dSCornelia Huck } 14979afc36dSCornelia Huck 150de13d216SCornelia Huck void s390_crw_mchk(void) 15179afc36dSCornelia Huck { 15279afc36dSCornelia Huck if (kvm_enabled()) { 153de13d216SCornelia Huck kvm_s390_crw_mchk(); 15479afc36dSCornelia Huck } else { 155de13d216SCornelia Huck S390CPU *dummy_cpu = s390_cpu_addr2state(0); 156de13d216SCornelia Huck 157de13d216SCornelia Huck cpu_inject_crw_mchk(dummy_cpu); 15879afc36dSCornelia Huck } 15979afc36dSCornelia Huck } 16079afc36dSCornelia Huck 161000a1a38SChristian Borntraeger #endif 162