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" 13f16bbb9bSDavid 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 74*6482b0ffSDavid Hildenbrand env->pending_int |= INTERRUPT_EXT_SERVICE; 75*6482b0ffSDavid Hildenbrand cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 76*6482b0ffSDavid Hildenbrand } 77*6482b0ffSDavid Hildenbrand 78*6482b0ffSDavid Hildenbrand void cpu_inject_clock_comparator(S390CPU *cpu) 79*6482b0ffSDavid Hildenbrand { 80*6482b0ffSDavid Hildenbrand CPUS390XState *env = &cpu->env; 81*6482b0ffSDavid Hildenbrand 82*6482b0ffSDavid Hildenbrand env->pending_int |= INTERRUPT_EXT_CLOCK_COMPARATOR; 83*6482b0ffSDavid Hildenbrand cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 84*6482b0ffSDavid Hildenbrand } 85*6482b0ffSDavid Hildenbrand 86*6482b0ffSDavid Hildenbrand void cpu_inject_cpu_timer(S390CPU *cpu) 87*6482b0ffSDavid Hildenbrand { 88*6482b0ffSDavid Hildenbrand CPUS390XState *env = &cpu->env; 89*6482b0ffSDavid Hildenbrand 90*6482b0ffSDavid Hildenbrand env->pending_int |= INTERRUPT_EXT_CPU_TIMER; 91bd3f16acSPaolo Bonzini cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 92bd3f16acSPaolo Bonzini } 93bd3f16acSPaolo Bonzini 94bd3f16acSPaolo Bonzini static void cpu_inject_io(S390CPU *cpu, uint16_t subchannel_id, 95bd3f16acSPaolo Bonzini uint16_t subchannel_number, 96bd3f16acSPaolo Bonzini uint32_t io_int_parm, uint32_t io_int_word) 97bd3f16acSPaolo Bonzini { 98bd3f16acSPaolo Bonzini CPUS390XState *env = &cpu->env; 99bd3f16acSPaolo Bonzini int isc = IO_INT_WORD_ISC(io_int_word); 100bd3f16acSPaolo Bonzini 101bd3f16acSPaolo Bonzini if (env->io_index[isc] == MAX_IO_QUEUE - 1) { 102bd3f16acSPaolo Bonzini /* ugh - can't queue anymore. Let's drop. */ 103bd3f16acSPaolo Bonzini return; 104bd3f16acSPaolo Bonzini } 105bd3f16acSPaolo Bonzini 106bd3f16acSPaolo Bonzini env->io_index[isc]++; 107bd3f16acSPaolo Bonzini assert(env->io_index[isc] < MAX_IO_QUEUE); 108bd3f16acSPaolo Bonzini 109bd3f16acSPaolo Bonzini env->io_queue[env->io_index[isc]][isc].id = subchannel_id; 110bd3f16acSPaolo Bonzini env->io_queue[env->io_index[isc]][isc].nr = subchannel_number; 111bd3f16acSPaolo Bonzini env->io_queue[env->io_index[isc]][isc].parm = io_int_parm; 112bd3f16acSPaolo Bonzini env->io_queue[env->io_index[isc]][isc].word = io_int_word; 113bd3f16acSPaolo Bonzini 114bd3f16acSPaolo Bonzini env->pending_int |= INTERRUPT_IO; 115bd3f16acSPaolo Bonzini cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 116bd3f16acSPaolo Bonzini } 117bd3f16acSPaolo Bonzini 118bd3f16acSPaolo Bonzini static void cpu_inject_crw_mchk(S390CPU *cpu) 119bd3f16acSPaolo Bonzini { 120bd3f16acSPaolo Bonzini CPUS390XState *env = &cpu->env; 121bd3f16acSPaolo Bonzini 122bd3f16acSPaolo Bonzini if (env->mchk_index == MAX_MCHK_QUEUE - 1) { 123bd3f16acSPaolo Bonzini /* ugh - can't queue anymore. Let's drop. */ 124bd3f16acSPaolo Bonzini return; 125bd3f16acSPaolo Bonzini } 126bd3f16acSPaolo Bonzini 127bd3f16acSPaolo Bonzini env->mchk_index++; 128bd3f16acSPaolo Bonzini assert(env->mchk_index < MAX_MCHK_QUEUE); 129bd3f16acSPaolo Bonzini 130bd3f16acSPaolo Bonzini env->mchk_queue[env->mchk_index].type = 1; 131bd3f16acSPaolo Bonzini 132bd3f16acSPaolo Bonzini env->pending_int |= INTERRUPT_MCHK; 133bd3f16acSPaolo Bonzini cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 134bd3f16acSPaolo Bonzini } 135000a1a38SChristian Borntraeger 13679afc36dSCornelia Huck /* 13779afc36dSCornelia Huck * All of the following interrupts are floating, i.e. not per-vcpu. 138de13d216SCornelia Huck * We just need a dummy cpustate in order to be able to inject in the 139de13d216SCornelia Huck * non-kvm case. 14079afc36dSCornelia Huck */ 141000a1a38SChristian Borntraeger void s390_sclp_extint(uint32_t parm) 142000a1a38SChristian Borntraeger { 143de13d216SCornelia Huck if (kvm_enabled()) { 144de13d216SCornelia Huck kvm_s390_service_interrupt(parm); 145de13d216SCornelia Huck } else { 146000a1a38SChristian Borntraeger S390CPU *dummy_cpu = s390_cpu_addr2state(0); 147000a1a38SChristian Borntraeger 148f9466733SAndreas Färber cpu_inject_ext(dummy_cpu, EXT_SERVICE, parm, 0); 149000a1a38SChristian Borntraeger } 150000a1a38SChristian Borntraeger } 15179afc36dSCornelia Huck 152de13d216SCornelia Huck void s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr, 153de13d216SCornelia Huck uint32_t io_int_parm, uint32_t io_int_word) 15479afc36dSCornelia Huck { 15579afc36dSCornelia Huck if (kvm_enabled()) { 156de13d216SCornelia Huck kvm_s390_io_interrupt(subchannel_id, subchannel_nr, io_int_parm, 15779afc36dSCornelia Huck io_int_word); 15879afc36dSCornelia Huck } else { 159de13d216SCornelia Huck S390CPU *dummy_cpu = s390_cpu_addr2state(0); 160de13d216SCornelia Huck 161de13d216SCornelia Huck cpu_inject_io(dummy_cpu, subchannel_id, subchannel_nr, io_int_parm, 16279afc36dSCornelia Huck io_int_word); 16379afc36dSCornelia Huck } 16479afc36dSCornelia Huck } 16579afc36dSCornelia Huck 166de13d216SCornelia Huck void s390_crw_mchk(void) 16779afc36dSCornelia Huck { 16879afc36dSCornelia Huck if (kvm_enabled()) { 169de13d216SCornelia Huck kvm_s390_crw_mchk(); 17079afc36dSCornelia Huck } else { 171de13d216SCornelia Huck S390CPU *dummy_cpu = s390_cpu_addr2state(0); 172de13d216SCornelia Huck 173de13d216SCornelia Huck cpu_inject_crw_mchk(dummy_cpu); 17479afc36dSCornelia Huck } 17579afc36dSCornelia Huck } 17679afc36dSCornelia Huck 177000a1a38SChristian Borntraeger #endif 178