qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

interrupt.c (5924B)


      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 "cpu.h"
     12 #include "kvm/kvm_s390x.h"
     13 #include "s390x-internal.h"
     14 #include "exec/exec-all.h"
     15 #include "sysemu/kvm.h"
     16 #include "sysemu/tcg.h"
     17 #include "hw/s390x/ioinst.h"
     18 #include "tcg/tcg_s390x.h"
     19 #if !defined(CONFIG_USER_ONLY)
     20 #include "hw/s390x/s390_flic.h"
     21 #endif
     22 
     23 /* Ensure to exit the TB after this call! */
     24 void trigger_pgm_exception(CPUS390XState *env, uint32_t code)
     25 {
     26     CPUState *cs = env_cpu(env);
     27 
     28     cs->exception_index = EXCP_PGM;
     29     env->int_pgm_code = code;
     30     /* env->int_pgm_ilen is already set, or will be set during unwinding */
     31 }
     32 
     33 void s390_program_interrupt(CPUS390XState *env, uint32_t code, uintptr_t ra)
     34 {
     35     if (kvm_enabled()) {
     36         kvm_s390_program_interrupt(env_archcpu(env), code);
     37     } else if (tcg_enabled()) {
     38         tcg_s390_program_interrupt(env, code, ra);
     39     } else {
     40         g_assert_not_reached();
     41     }
     42 }
     43 
     44 #if !defined(CONFIG_USER_ONLY)
     45 void cpu_inject_clock_comparator(S390CPU *cpu)
     46 {
     47     CPUS390XState *env = &cpu->env;
     48 
     49     env->pending_int |= INTERRUPT_EXT_CLOCK_COMPARATOR;
     50     cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
     51 }
     52 
     53 void cpu_inject_cpu_timer(S390CPU *cpu)
     54 {
     55     CPUS390XState *env = &cpu->env;
     56 
     57     env->pending_int |= INTERRUPT_EXT_CPU_TIMER;
     58     cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
     59 }
     60 
     61 void cpu_inject_emergency_signal(S390CPU *cpu, uint16_t src_cpu_addr)
     62 {
     63     CPUS390XState *env = &cpu->env;
     64 
     65     g_assert(src_cpu_addr < S390_MAX_CPUS);
     66     set_bit(src_cpu_addr, env->emergency_signals);
     67 
     68     env->pending_int |= INTERRUPT_EMERGENCY_SIGNAL;
     69     cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
     70 }
     71 
     72 int cpu_inject_external_call(S390CPU *cpu, uint16_t src_cpu_addr)
     73 {
     74     CPUS390XState *env = &cpu->env;
     75 
     76     g_assert(src_cpu_addr < S390_MAX_CPUS);
     77     if (env->pending_int & INTERRUPT_EXTERNAL_CALL) {
     78         return -EBUSY;
     79     }
     80     env->external_call_addr = src_cpu_addr;
     81 
     82     env->pending_int |= INTERRUPT_EXTERNAL_CALL;
     83     cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
     84     return 0;
     85 }
     86 
     87 void cpu_inject_restart(S390CPU *cpu)
     88 {
     89     CPUS390XState *env = &cpu->env;
     90 
     91     if (kvm_enabled()) {
     92         kvm_s390_restart_interrupt(cpu);
     93         return;
     94     }
     95 
     96     env->pending_int |= INTERRUPT_RESTART;
     97     cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
     98 }
     99 
    100 void cpu_inject_stop(S390CPU *cpu)
    101 {
    102     CPUS390XState *env = &cpu->env;
    103 
    104     if (kvm_enabled()) {
    105         kvm_s390_stop_interrupt(cpu);
    106         return;
    107     }
    108 
    109     env->pending_int |= INTERRUPT_STOP;
    110     cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
    111 }
    112 
    113 /*
    114  * All of the following interrupts are floating, i.e. not per-vcpu.
    115  * We just need a dummy cpustate in order to be able to inject in the
    116  * non-kvm case.
    117  */
    118 void s390_sclp_extint(uint32_t parm)
    119 {
    120     S390FLICState *fs = s390_get_flic();
    121     S390FLICStateClass *fsc = s390_get_flic_class(fs);
    122 
    123     fsc->inject_service(fs, parm);
    124 }
    125 
    126 void s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr,
    127                        uint32_t io_int_parm, uint32_t io_int_word)
    128 {
    129     S390FLICState *fs = s390_get_flic();
    130     S390FLICStateClass *fsc = s390_get_flic_class(fs);
    131 
    132     fsc->inject_io(fs, subchannel_id, subchannel_nr, io_int_parm, io_int_word);
    133 }
    134 
    135 void s390_crw_mchk(void)
    136 {
    137     S390FLICState *fs = s390_get_flic();
    138     S390FLICStateClass *fsc = s390_get_flic_class(fs);
    139 
    140     fsc->inject_crw_mchk(fs);
    141 }
    142 
    143 bool s390_cpu_has_mcck_int(S390CPU *cpu)
    144 {
    145     QEMUS390FLICState *flic = s390_get_qemu_flic(s390_get_flic());
    146     CPUS390XState *env = &cpu->env;
    147 
    148     if (!(env->psw.mask & PSW_MASK_MCHECK)) {
    149         return false;
    150     }
    151 
    152     /* for now we only support channel report machine checks (floating) */
    153     if (qemu_s390_flic_has_crw_mchk(flic) &&
    154         (env->cregs[14] & CR14_CHANNEL_REPORT_SC)) {
    155         return true;
    156     }
    157 
    158     return false;
    159 }
    160 
    161 bool s390_cpu_has_ext_int(S390CPU *cpu)
    162 {
    163     QEMUS390FLICState *flic = s390_get_qemu_flic(s390_get_flic());
    164     CPUS390XState *env = &cpu->env;
    165 
    166     if (!(env->psw.mask & PSW_MASK_EXT)) {
    167         return false;
    168     }
    169 
    170     if ((env->pending_int & INTERRUPT_EMERGENCY_SIGNAL) &&
    171         (env->cregs[0] & CR0_EMERGENCY_SIGNAL_SC)) {
    172         return true;
    173     }
    174 
    175     if ((env->pending_int & INTERRUPT_EXTERNAL_CALL) &&
    176         (env->cregs[0] & CR0_EXTERNAL_CALL_SC)) {
    177         return true;
    178     }
    179 
    180     if ((env->pending_int & INTERRUPT_EXTERNAL_CALL) &&
    181         (env->cregs[0] & CR0_EXTERNAL_CALL_SC)) {
    182         return true;
    183     }
    184 
    185     if ((env->pending_int & INTERRUPT_EXT_CLOCK_COMPARATOR) &&
    186         (env->cregs[0] & CR0_CKC_SC)) {
    187         return true;
    188     }
    189 
    190     if ((env->pending_int & INTERRUPT_EXT_CPU_TIMER) &&
    191         (env->cregs[0] & CR0_CPU_TIMER_SC)) {
    192         return true;
    193     }
    194 
    195     if (qemu_s390_flic_has_service(flic) &&
    196         (env->cregs[0] & CR0_SERVICE_SC)) {
    197         return true;
    198     }
    199 
    200     return false;
    201 }
    202 
    203 bool s390_cpu_has_io_int(S390CPU *cpu)
    204 {
    205     QEMUS390FLICState *flic = s390_get_qemu_flic(s390_get_flic());
    206     CPUS390XState *env = &cpu->env;
    207 
    208     if (!(env->psw.mask & PSW_MASK_IO)) {
    209         return false;
    210     }
    211 
    212     return qemu_s390_flic_has_io(flic, env->cregs[6]);
    213 }
    214 
    215 bool s390_cpu_has_restart_int(S390CPU *cpu)
    216 {
    217     CPUS390XState *env = &cpu->env;
    218 
    219     return env->pending_int & INTERRUPT_RESTART;
    220 }
    221 
    222 bool s390_cpu_has_stop_int(S390CPU *cpu)
    223 {
    224     CPUS390XState *env = &cpu->env;
    225 
    226     return env->pending_int & INTERRUPT_STOP;
    227 }
    228 #endif
    229 
    230 bool s390_cpu_has_int(S390CPU *cpu)
    231 {
    232 #ifndef CONFIG_USER_ONLY
    233     if (!tcg_enabled()) {
    234         return false;
    235     }
    236     return s390_cpu_has_mcck_int(cpu) ||
    237            s390_cpu_has_ext_int(cpu) ||
    238            s390_cpu_has_io_int(cpu) ||
    239            s390_cpu_has_restart_int(cpu) ||
    240            s390_cpu_has_stop_int(cpu);
    241 #else
    242     return false;
    243 #endif
    244 }