qemu/target/s390x/interrupt.c
<<
>>
Prefs
   1/*
   2 * QEMU S/390 Interrupt support
   3 *
   4 * Copyright IBM Corp. 2012, 2014
   5 *
   6 * This work is licensed under the terms of the GNU GPL, version 2 or (at your
   7 * option) any later version.  See the COPYING file in the top-level directory.
   8 */
   9
  10#include "qemu/osdep.h"
  11#include "qemu/log.h"
  12#include "cpu.h"
  13#include "exec/exec-all.h"
  14#include "sysemu/kvm.h"
  15#include "hw/s390x/ioinst.h"
  16
  17/* Ensure to exit the TB after this call! */
  18void trigger_pgm_exception(CPUS390XState *env, uint32_t code, uint32_t ilen)
  19{
  20    CPUState *cs = CPU(s390_env_get_cpu(env));
  21
  22    cs->exception_index = EXCP_PGM;
  23    env->int_pgm_code = code;
  24    env->int_pgm_ilen = ilen;
  25}
  26
  27static void tcg_s390_program_interrupt(CPUS390XState *env, uint32_t code,
  28                                       int ilen)
  29{
  30#ifdef CONFIG_TCG
  31    trigger_pgm_exception(env, code, ilen);
  32    cpu_loop_exit(CPU(s390_env_get_cpu(env)));
  33#else
  34    g_assert_not_reached();
  35#endif
  36}
  37
  38void program_interrupt(CPUS390XState *env, uint32_t code, int ilen)
  39{
  40    S390CPU *cpu = s390_env_get_cpu(env);
  41
  42    qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
  43                  env->psw.addr);
  44
  45    if (kvm_enabled()) {
  46        kvm_s390_program_interrupt(cpu, code);
  47    } else if (tcg_enabled()) {
  48        tcg_s390_program_interrupt(env, code, ilen);
  49    } else {
  50        g_assert_not_reached();
  51    }
  52}
  53
  54#if !defined(CONFIG_USER_ONLY)
  55void cpu_inject_ext(S390CPU *cpu, uint32_t code, uint32_t param,
  56                    uint64_t param64)
  57{
  58    CPUS390XState *env = &cpu->env;
  59
  60    if (env->ext_index == MAX_EXT_QUEUE - 1) {
  61        /* ugh - can't queue anymore. Let's drop. */
  62        return;
  63    }
  64
  65    env->ext_index++;
  66    assert(env->ext_index < MAX_EXT_QUEUE);
  67
  68    env->ext_queue[env->ext_index].code = code;
  69    env->ext_queue[env->ext_index].param = param;
  70    env->ext_queue[env->ext_index].param64 = param64;
  71
  72    env->pending_int |= INTERRUPT_EXT;
  73    cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
  74}
  75
  76static void cpu_inject_io(S390CPU *cpu, uint16_t subchannel_id,
  77                          uint16_t subchannel_number,
  78                          uint32_t io_int_parm, uint32_t io_int_word)
  79{
  80    CPUS390XState *env = &cpu->env;
  81    int isc = IO_INT_WORD_ISC(io_int_word);
  82
  83    if (env->io_index[isc] == MAX_IO_QUEUE - 1) {
  84        /* ugh - can't queue anymore. Let's drop. */
  85        return;
  86    }
  87
  88    env->io_index[isc]++;
  89    assert(env->io_index[isc] < MAX_IO_QUEUE);
  90
  91    env->io_queue[env->io_index[isc]][isc].id = subchannel_id;
  92    env->io_queue[env->io_index[isc]][isc].nr = subchannel_number;
  93    env->io_queue[env->io_index[isc]][isc].parm = io_int_parm;
  94    env->io_queue[env->io_index[isc]][isc].word = io_int_word;
  95
  96    env->pending_int |= INTERRUPT_IO;
  97    cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
  98}
  99
 100static void cpu_inject_crw_mchk(S390CPU *cpu)
 101{
 102    CPUS390XState *env = &cpu->env;
 103
 104    if (env->mchk_index == MAX_MCHK_QUEUE - 1) {
 105        /* ugh - can't queue anymore. Let's drop. */
 106        return;
 107    }
 108
 109    env->mchk_index++;
 110    assert(env->mchk_index < MAX_MCHK_QUEUE);
 111
 112    env->mchk_queue[env->mchk_index].type = 1;
 113
 114    env->pending_int |= INTERRUPT_MCHK;
 115    cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
 116}
 117
 118/*
 119 * All of the following interrupts are floating, i.e. not per-vcpu.
 120 * We just need a dummy cpustate in order to be able to inject in the
 121 * non-kvm case.
 122 */
 123void s390_sclp_extint(uint32_t parm)
 124{
 125    if (kvm_enabled()) {
 126        kvm_s390_service_interrupt(parm);
 127    } else {
 128        S390CPU *dummy_cpu = s390_cpu_addr2state(0);
 129
 130        cpu_inject_ext(dummy_cpu, EXT_SERVICE, parm, 0);
 131    }
 132}
 133
 134void s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr,
 135                       uint32_t io_int_parm, uint32_t io_int_word)
 136{
 137    if (kvm_enabled()) {
 138        kvm_s390_io_interrupt(subchannel_id, subchannel_nr, io_int_parm,
 139                              io_int_word);
 140    } else {
 141        S390CPU *dummy_cpu = s390_cpu_addr2state(0);
 142
 143        cpu_inject_io(dummy_cpu, subchannel_id, subchannel_nr, io_int_parm,
 144                      io_int_word);
 145    }
 146}
 147
 148void s390_crw_mchk(void)
 149{
 150    if (kvm_enabled()) {
 151        kvm_s390_crw_mchk();
 152    } else {
 153        S390CPU *dummy_cpu = s390_cpu_addr2state(0);
 154
 155        cpu_inject_crw_mchk(dummy_cpu);
 156    }
 157}
 158
 159#endif
 160