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) 57*d516f74cSDavid Hildenbrand static void cpu_inject_service(S390CPU *cpu, uint32_t param) 58bd3f16acSPaolo Bonzini { 59bd3f16acSPaolo Bonzini CPUS390XState *env = &cpu->env; 60bd3f16acSPaolo Bonzini 61*d516f74cSDavid Hildenbrand /* multiplexing is good enough for sclp - kvm does it internally as well*/ 62*d516f74cSDavid Hildenbrand env->service_param |= param; 63bd3f16acSPaolo Bonzini 646482b0ffSDavid Hildenbrand env->pending_int |= INTERRUPT_EXT_SERVICE; 656482b0ffSDavid Hildenbrand cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 666482b0ffSDavid Hildenbrand } 676482b0ffSDavid Hildenbrand 686482b0ffSDavid Hildenbrand void cpu_inject_clock_comparator(S390CPU *cpu) 696482b0ffSDavid Hildenbrand { 706482b0ffSDavid Hildenbrand CPUS390XState *env = &cpu->env; 716482b0ffSDavid Hildenbrand 726482b0ffSDavid Hildenbrand env->pending_int |= INTERRUPT_EXT_CLOCK_COMPARATOR; 736482b0ffSDavid Hildenbrand cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 746482b0ffSDavid Hildenbrand } 756482b0ffSDavid Hildenbrand 766482b0ffSDavid Hildenbrand void cpu_inject_cpu_timer(S390CPU *cpu) 776482b0ffSDavid Hildenbrand { 786482b0ffSDavid Hildenbrand CPUS390XState *env = &cpu->env; 796482b0ffSDavid Hildenbrand 806482b0ffSDavid Hildenbrand env->pending_int |= INTERRUPT_EXT_CPU_TIMER; 81bd3f16acSPaolo Bonzini cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 82bd3f16acSPaolo Bonzini } 83bd3f16acSPaolo Bonzini 84bd3f16acSPaolo Bonzini static void cpu_inject_io(S390CPU *cpu, uint16_t subchannel_id, 85bd3f16acSPaolo Bonzini uint16_t subchannel_number, 86bd3f16acSPaolo Bonzini uint32_t io_int_parm, uint32_t io_int_word) 87bd3f16acSPaolo Bonzini { 88bd3f16acSPaolo Bonzini CPUS390XState *env = &cpu->env; 89bd3f16acSPaolo Bonzini int isc = IO_INT_WORD_ISC(io_int_word); 90bd3f16acSPaolo Bonzini 91bd3f16acSPaolo Bonzini if (env->io_index[isc] == MAX_IO_QUEUE - 1) { 92bd3f16acSPaolo Bonzini /* ugh - can't queue anymore. Let's drop. */ 93bd3f16acSPaolo Bonzini return; 94bd3f16acSPaolo Bonzini } 95bd3f16acSPaolo Bonzini 96bd3f16acSPaolo Bonzini env->io_index[isc]++; 97bd3f16acSPaolo Bonzini assert(env->io_index[isc] < MAX_IO_QUEUE); 98bd3f16acSPaolo Bonzini 99bd3f16acSPaolo Bonzini env->io_queue[env->io_index[isc]][isc].id = subchannel_id; 100bd3f16acSPaolo Bonzini env->io_queue[env->io_index[isc]][isc].nr = subchannel_number; 101bd3f16acSPaolo Bonzini env->io_queue[env->io_index[isc]][isc].parm = io_int_parm; 102bd3f16acSPaolo Bonzini env->io_queue[env->io_index[isc]][isc].word = io_int_word; 103bd3f16acSPaolo Bonzini 104bd3f16acSPaolo Bonzini env->pending_int |= INTERRUPT_IO; 105bd3f16acSPaolo Bonzini cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 106bd3f16acSPaolo Bonzini } 107bd3f16acSPaolo Bonzini 108bd3f16acSPaolo Bonzini static void cpu_inject_crw_mchk(S390CPU *cpu) 109bd3f16acSPaolo Bonzini { 110bd3f16acSPaolo Bonzini CPUS390XState *env = &cpu->env; 111bd3f16acSPaolo Bonzini 112bd3f16acSPaolo Bonzini if (env->mchk_index == MAX_MCHK_QUEUE - 1) { 113bd3f16acSPaolo Bonzini /* ugh - can't queue anymore. Let's drop. */ 114bd3f16acSPaolo Bonzini return; 115bd3f16acSPaolo Bonzini } 116bd3f16acSPaolo Bonzini 117bd3f16acSPaolo Bonzini env->mchk_index++; 118bd3f16acSPaolo Bonzini assert(env->mchk_index < MAX_MCHK_QUEUE); 119bd3f16acSPaolo Bonzini 120bd3f16acSPaolo Bonzini env->mchk_queue[env->mchk_index].type = 1; 121bd3f16acSPaolo Bonzini 122bd3f16acSPaolo Bonzini env->pending_int |= INTERRUPT_MCHK; 123bd3f16acSPaolo Bonzini cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 124bd3f16acSPaolo Bonzini } 125000a1a38SChristian Borntraeger 12679afc36dSCornelia Huck /* 12779afc36dSCornelia Huck * All of the following interrupts are floating, i.e. not per-vcpu. 128de13d216SCornelia Huck * We just need a dummy cpustate in order to be able to inject in the 129de13d216SCornelia Huck * non-kvm case. 13079afc36dSCornelia Huck */ 131000a1a38SChristian Borntraeger void s390_sclp_extint(uint32_t parm) 132000a1a38SChristian Borntraeger { 133de13d216SCornelia Huck if (kvm_enabled()) { 134de13d216SCornelia Huck kvm_s390_service_interrupt(parm); 135de13d216SCornelia Huck } else { 136000a1a38SChristian Borntraeger S390CPU *dummy_cpu = s390_cpu_addr2state(0); 137000a1a38SChristian Borntraeger 138*d516f74cSDavid Hildenbrand cpu_inject_service(dummy_cpu, parm); 139000a1a38SChristian Borntraeger } 140000a1a38SChristian Borntraeger } 14179afc36dSCornelia Huck 142de13d216SCornelia Huck void s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr, 143de13d216SCornelia Huck uint32_t io_int_parm, uint32_t io_int_word) 14479afc36dSCornelia Huck { 14579afc36dSCornelia Huck if (kvm_enabled()) { 146de13d216SCornelia Huck kvm_s390_io_interrupt(subchannel_id, subchannel_nr, io_int_parm, 14779afc36dSCornelia Huck io_int_word); 14879afc36dSCornelia Huck } else { 149de13d216SCornelia Huck S390CPU *dummy_cpu = s390_cpu_addr2state(0); 150de13d216SCornelia Huck 151de13d216SCornelia Huck cpu_inject_io(dummy_cpu, subchannel_id, subchannel_nr, io_int_parm, 15279afc36dSCornelia Huck io_int_word); 15379afc36dSCornelia Huck } 15479afc36dSCornelia Huck } 15579afc36dSCornelia Huck 156de13d216SCornelia Huck void s390_crw_mchk(void) 15779afc36dSCornelia Huck { 15879afc36dSCornelia Huck if (kvm_enabled()) { 159de13d216SCornelia Huck kvm_s390_crw_mchk(); 16079afc36dSCornelia Huck } else { 161de13d216SCornelia Huck S390CPU *dummy_cpu = s390_cpu_addr2state(0); 162de13d216SCornelia Huck 163de13d216SCornelia Huck cpu_inject_crw_mchk(dummy_cpu); 16479afc36dSCornelia Huck } 16579afc36dSCornelia Huck } 16679afc36dSCornelia Huck 167000a1a38SChristian Borntraeger #endif 168