Fix Sparc32 interrupt handling
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3110 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
		
							parent
							
								
									ccf1d14a1e
								
							
						
					
					
						commit
						327ac2e797
					
				| 
						 | 
					@ -461,6 +461,9 @@ int cpu_exec(CPUState *env1)
 | 
				
			||||||
			    env->interrupt_request &= ~CPU_INTERRUPT_HARD;
 | 
								    env->interrupt_request &= ~CPU_INTERRUPT_HARD;
 | 
				
			||||||
			    do_interrupt(env->interrupt_index);
 | 
								    do_interrupt(env->interrupt_index);
 | 
				
			||||||
			    env->interrupt_index = 0;
 | 
								    env->interrupt_index = 0;
 | 
				
			||||||
 | 
					#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
 | 
				
			||||||
 | 
					                            cpu_check_irqs(env);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
#if defined(__sparc__) && !defined(HOST_SOLARIS)
 | 
					#if defined(__sparc__) && !defined(HOST_SOLARIS)
 | 
				
			||||||
                            tmp_T0 = 0;
 | 
					                            tmp_T0 = 0;
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -104,6 +104,7 @@ static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint
 | 
				
			||||||
	    val |= 80000000;
 | 
						    val |= 80000000;
 | 
				
			||||||
	val &= 0xfffe0000;
 | 
						val &= 0xfffe0000;
 | 
				
			||||||
	s->intreg_pending[cpu] &= ~val;
 | 
						s->intreg_pending[cpu] &= ~val;
 | 
				
			||||||
 | 
					        slavio_check_interrupts(s);
 | 
				
			||||||
	DPRINTF("Cleared cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]);
 | 
						DPRINTF("Cleared cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]);
 | 
				
			||||||
	break;
 | 
						break;
 | 
				
			||||||
    case 2: // set softint
 | 
					    case 2: // set softint
 | 
				
			||||||
| 
						 | 
					@ -175,10 +176,12 @@ static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uin
 | 
				
			||||||
	val &= ~0x4fb2007f;
 | 
						val &= ~0x4fb2007f;
 | 
				
			||||||
	s->intregm_disabled |= val;
 | 
						s->intregm_disabled |= val;
 | 
				
			||||||
	s->intregm_pending &= ~val;
 | 
						s->intregm_pending &= ~val;
 | 
				
			||||||
 | 
					        slavio_check_interrupts(s);
 | 
				
			||||||
	DPRINTF("Disabled master irq mask %x, curmask %x\n", val, s->intregm_disabled);
 | 
						DPRINTF("Disabled master irq mask %x, curmask %x\n", val, s->intregm_disabled);
 | 
				
			||||||
	break;
 | 
						break;
 | 
				
			||||||
    case 4:
 | 
					    case 4:
 | 
				
			||||||
	s->target_cpu = val & (MAX_CPUS - 1);
 | 
						s->target_cpu = val & (MAX_CPUS - 1);
 | 
				
			||||||
 | 
					        slavio_check_interrupts(s);
 | 
				
			||||||
	DPRINTF("Set master irq cpu %d\n", s->target_cpu);
 | 
						DPRINTF("Set master irq cpu %d\n", s->target_cpu);
 | 
				
			||||||
	break;
 | 
						break;
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
| 
						 | 
					@ -227,53 +230,36 @@ void slavio_irq_info(void *opaque)
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void raise_pil(SLAVIO_INTCTLState *s, unsigned int pil,
 | 
					 | 
				
			||||||
                      unsigned int cpu)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    qemu_irq irq;
 | 
					 | 
				
			||||||
    unsigned int oldmax;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    irq = s->cpu_irqs[cpu][pil];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef DEBUG_IRQ_COUNT
 | 
					 | 
				
			||||||
    s->irq_count[pil]++;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    oldmax = s->pil_out[cpu];
 | 
					 | 
				
			||||||
    if (oldmax > 0 && oldmax != pil)
 | 
					 | 
				
			||||||
        qemu_irq_lower(s->cpu_irqs[cpu][oldmax]);
 | 
					 | 
				
			||||||
    s->pil_out[cpu] = pil;
 | 
					 | 
				
			||||||
    if (pil > 0)
 | 
					 | 
				
			||||||
        qemu_irq_raise(irq);
 | 
					 | 
				
			||||||
    DPRINTF("cpu %d pil %d\n", cpu, pil);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void slavio_check_interrupts(void *opaque)
 | 
					static void slavio_check_interrupts(void *opaque)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    SLAVIO_INTCTLState *s = opaque;
 | 
					    SLAVIO_INTCTLState *s = opaque;
 | 
				
			||||||
    uint32_t pending = s->intregm_pending;
 | 
					    uint32_t pending = s->intregm_pending, pil_pending;
 | 
				
			||||||
    unsigned int i, j, max = 0;
 | 
					    unsigned int i, j;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pending &= ~s->intregm_disabled;
 | 
					    pending &= ~s->intregm_disabled;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    DPRINTF("pending %x disabled %x\n", pending, s->intregm_disabled);
 | 
					    DPRINTF("pending %x disabled %x\n", pending, s->intregm_disabled);
 | 
				
			||||||
    for (i = 0; i < MAX_CPUS; i++) {
 | 
					    for (i = 0; i < MAX_CPUS; i++) {
 | 
				
			||||||
        max = 0;
 | 
					        pil_pending = 0;
 | 
				
			||||||
        if (pending && !(s->intregm_disabled & 0x80000000) &&
 | 
					        if (pending && !(s->intregm_disabled & 0x80000000) &&
 | 
				
			||||||
            (i == s->target_cpu)) {
 | 
					            (i == s->target_cpu)) {
 | 
				
			||||||
            for (j = 0; j < 32; j++) {
 | 
					            for (j = 0; j < 32; j++) {
 | 
				
			||||||
                if (pending & (1 << j)) {
 | 
					                if (pending & (1 << j))
 | 
				
			||||||
                    if (max < s->intbit_to_level[j])
 | 
					                    pil_pending |= 1 << s->intbit_to_level[j];
 | 
				
			||||||
                        max = s->intbit_to_level[j];
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        }
 | 
					        pil_pending |= (s->intreg_pending[i] >> 16) & 0xfffe;
 | 
				
			||||||
        for (j = 17; j < 32; j++) {
 | 
					
 | 
				
			||||||
            if (s->intreg_pending[i] & (1 << j)) {
 | 
					        for (j = 0; j < MAX_PILS; j++) {
 | 
				
			||||||
                if (max < j - 16)
 | 
					            if (pil_pending & (1 << j)) {
 | 
				
			||||||
                    max = j - 16;
 | 
					                if (!(s->pil_out[i] & (1 << j)))
 | 
				
			||||||
 | 
					                    qemu_irq_raise(s->cpu_irqs[i][j]);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                if (s->pil_out[i] & (1 << j))
 | 
				
			||||||
 | 
					                    qemu_irq_lower(s->cpu_irqs[i][j]);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        raise_pil(s, max, i);
 | 
					        s->pil_out[i] = pil_pending;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -291,6 +277,9 @@ static void slavio_set_irq(void *opaque, int irq, int level)
 | 
				
			||||||
            level);
 | 
					            level);
 | 
				
			||||||
    if (pil > 0) {
 | 
					    if (pil > 0) {
 | 
				
			||||||
        if (level) {
 | 
					        if (level) {
 | 
				
			||||||
 | 
					#ifdef DEBUG_IRQ_COUNT
 | 
				
			||||||
 | 
					            s->irq_count[pil]++;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
            s->intregm_pending |= mask;
 | 
					            s->intregm_pending |= mask;
 | 
				
			||||||
            s->intreg_pending[s->target_cpu] |= 1 << pil;
 | 
					            s->intreg_pending[s->target_cpu] |= 1 << pil;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
| 
						 | 
					@ -342,6 +331,7 @@ static int slavio_intctl_load(QEMUFile *f, void *opaque, int version_id)
 | 
				
			||||||
    qemu_get_be32s(f, &s->intregm_pending);
 | 
					    qemu_get_be32s(f, &s->intregm_pending);
 | 
				
			||||||
    qemu_get_be32s(f, &s->intregm_disabled);
 | 
					    qemu_get_be32s(f, &s->intregm_disabled);
 | 
				
			||||||
    qemu_get_be32s(f, &s->target_cpu);
 | 
					    qemu_get_be32s(f, &s->target_cpu);
 | 
				
			||||||
 | 
					    slavio_check_interrupts(s);
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -356,6 +346,7 @@ static void slavio_intctl_reset(void *opaque)
 | 
				
			||||||
    s->intregm_disabled = ~0xffb2007f;
 | 
					    s->intregm_disabled = ~0xffb2007f;
 | 
				
			||||||
    s->intregm_pending = 0;
 | 
					    s->intregm_pending = 0;
 | 
				
			||||||
    s->target_cpu = 0;
 | 
					    s->target_cpu = 0;
 | 
				
			||||||
 | 
					    slavio_check_interrupts(s);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg,
 | 
					void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										37
									
								
								hw/sun4m.c
								
								
								
								
							
							
						
						
									
										37
									
								
								hw/sun4m.c
								
								
								
								
							| 
						 | 
					@ -240,26 +240,41 @@ void irq_info()
 | 
				
			||||||
    slavio_irq_info(slavio_intctl);
 | 
					    slavio_irq_info(slavio_intctl);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void cpu_check_irqs(CPUState *env)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (env->pil_in && (env->interrupt_index == 0 ||
 | 
				
			||||||
 | 
					                        (env->interrupt_index & ~15) == TT_EXTINT)) {
 | 
				
			||||||
 | 
					        unsigned int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (i = 15; i > 0; i--) {
 | 
				
			||||||
 | 
					            if (env->pil_in & (1 << i)) {
 | 
				
			||||||
 | 
					                int old_interrupt = env->interrupt_index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                env->interrupt_index = TT_EXTINT | i;
 | 
				
			||||||
 | 
					                if (old_interrupt != env->interrupt_index)
 | 
				
			||||||
 | 
					                    cpu_interrupt(env, CPU_INTERRUPT_HARD);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else if (!env->pil_in && (env->interrupt_index & ~15) == TT_EXTINT) {
 | 
				
			||||||
 | 
					        env->interrupt_index = 0;
 | 
				
			||||||
 | 
					        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void cpu_set_irq(void *opaque, int irq, int level)
 | 
					static void cpu_set_irq(void *opaque, int irq, int level)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    CPUState *env = opaque;
 | 
					    CPUState *env = opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (level) {
 | 
					    if (level) {
 | 
				
			||||||
        DPRINTF("Raise CPU IRQ %d\n", irq);
 | 
					        DPRINTF("Raise CPU IRQ %d\n", irq);
 | 
				
			||||||
 | 
					 | 
				
			||||||
        env->halted = 0;
 | 
					        env->halted = 0;
 | 
				
			||||||
 | 
					        env->pil_in |= 1 << irq;
 | 
				
			||||||
        if (env->interrupt_index == 0 ||
 | 
					        cpu_check_irqs(env);
 | 
				
			||||||
            ((env->interrupt_index & ~15) == TT_EXTINT &&
 | 
					 | 
				
			||||||
             (env->interrupt_index & 15) < irq)) {
 | 
					 | 
				
			||||||
            env->interrupt_index = TT_EXTINT | irq;
 | 
					 | 
				
			||||||
            cpu_interrupt(env, CPU_INTERRUPT_HARD);
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            DPRINTF("Not triggered, pending exception %d\n",
 | 
					 | 
				
			||||||
                    env->interrupt_index);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        DPRINTF("Lower CPU IRQ %d\n", irq);
 | 
					        DPRINTF("Lower CPU IRQ %d\n", irq);
 | 
				
			||||||
 | 
					        env->pil_in &= ~(1 << irq);
 | 
				
			||||||
 | 
					        cpu_check_irqs(env);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -181,7 +181,8 @@ typedef struct CPUSPARCState {
 | 
				
			||||||
    int      psrs;     /* supervisor mode (extracted from PSR) */
 | 
					    int      psrs;     /* supervisor mode (extracted from PSR) */
 | 
				
			||||||
    int      psrps;    /* previous supervisor mode */
 | 
					    int      psrps;    /* previous supervisor mode */
 | 
				
			||||||
    int      psret;    /* enable traps */
 | 
					    int      psret;    /* enable traps */
 | 
				
			||||||
    uint32_t psrpil;   /* interrupt level */
 | 
					    uint32_t psrpil;   /* interrupt blocking level */
 | 
				
			||||||
 | 
					    uint32_t pil_in;   /* incoming interrupt level bitmap */
 | 
				
			||||||
    int      psref;    /* enable fpu */
 | 
					    int      psref;    /* enable fpu */
 | 
				
			||||||
    target_ulong version;
 | 
					    target_ulong version;
 | 
				
			||||||
    jmp_buf  jmp_env;
 | 
					    jmp_buf  jmp_env;
 | 
				
			||||||
| 
						 | 
					@ -306,6 +307,7 @@ void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
 | 
				
			||||||
void do_tick_set_count(void *opaque, uint64_t count);
 | 
					void do_tick_set_count(void *opaque, uint64_t count);
 | 
				
			||||||
uint64_t do_tick_get_count(void *opaque);
 | 
					uint64_t do_tick_get_count(void *opaque);
 | 
				
			||||||
void do_tick_set_limit(void *opaque, uint64_t limit);
 | 
					void do_tick_set_limit(void *opaque, uint64_t limit);
 | 
				
			||||||
 | 
					void cpu_check_irqs(CPUSPARCState *env);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CPUState CPUSPARCState
 | 
					#define CPUState CPUSPARCState
 | 
				
			||||||
#define cpu_init cpu_sparc_init
 | 
					#define cpu_init cpu_sparc_init
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue