diff options
-rw-r--r-- | cpu-exec.c | 12 | ||||
-rw-r--r-- | hw/openpic.c | 106 | ||||
-rw-r--r-- | hw/ppc.c | 126 | ||||
-rw-r--r-- | hw/ppc_chrp.c | 42 | ||||
-rw-r--r-- | hw/ppc_prep.c | 3 | ||||
-rw-r--r-- | target-ppc/cpu.h | 46 | ||||
-rw-r--r-- | target-ppc/helper.c | 16 | ||||
-rw-r--r-- | target-ppc/translate_init.c | 35 | ||||
-rw-r--r-- | vl.h | 20 |
9 files changed, 287 insertions, 119 deletions
diff --git a/cpu-exec.c b/cpu-exec.c index 0eabacd643..284cb92ae8 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -467,16 +467,14 @@ int cpu_exec(CPUState *env1) } #endif if (interrupt_request & CPU_INTERRUPT_HARD) { - if (ppc_hw_interrupt(env) == 1) { - /* Some exception was raised */ - if (env->pending_interrupts == 0) - env->interrupt_request &= ~CPU_INTERRUPT_HARD; + ppc_hw_interrupt(env); + if (env->pending_interrupts == 0) + env->interrupt_request &= ~CPU_INTERRUPT_HARD; #if defined(__sparc__) && !defined(HOST_SOLARIS) - tmp_T0 = 0; + tmp_T0 = 0; #else - T0 = 0; + T0 = 0; #endif - } } #elif defined(TARGET_MIPS) if ((interrupt_request & CPU_INTERRUPT_HARD) && diff --git a/hw/openpic.c b/hw/openpic.c index 3481f2d525..d52eb751e7 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -159,18 +159,18 @@ typedef struct IRQ_dst_t { uint32_t pcsr; /* CPU sensitivity register */ IRQ_queue_t raised; IRQ_queue_t servicing; - CPUState *env; + qemu_irq *irqs; } IRQ_dst_t; typedef struct openpic_t { PCIDevice pci_dev; - SetIRQFunc *set_irq; int mem_index; /* Global registers */ uint32_t frep; /* Feature reporting register */ uint32_t glbc; /* Global configuration register */ uint32_t micr; /* MPIC interrupt configuration register */ uint32_t veni; /* Vendor identification register */ + uint32_t pint; /* Processor initialization register */ uint32_t spve; /* Spurious vector register */ uint32_t tifr; /* Timer frequency reporting register */ /* Source registers */ @@ -196,6 +196,8 @@ typedef struct openpic_t { uint32_t mbr; /* Mailbox register */ } mailboxes[MAX_MAILBOXES]; #endif + /* IRQ out is used when in bypass mode (not implemented) */ + qemu_irq irq_out; } openpic_t; static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ) @@ -255,19 +257,34 @@ static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ) priority = IPVP_PRIORITY(src->ipvp); if (priority <= dst->pctp) { /* Too low priority */ + DPRINTF("%s: IRQ %d has too low priority on CPU %d\n", + __func__, n_IRQ, n_CPU); return; } if (IRQ_testbit(&dst->raised, n_IRQ)) { /* Interrupt miss */ + DPRINTF("%s: IRQ %d was missed on CPU %d\n", + __func__, n_IRQ, n_CPU); return; } set_bit(&src->ipvp, IPVP_ACTIVITY); IRQ_setbit(&dst->raised, n_IRQ); - if (priority > dst->raised.priority) { - IRQ_get_next(opp, &dst->raised); - DPRINTF("Raise CPU IRQ fn %p env %p\n", opp->set_irq, dst->env); - opp->set_irq(dst->env, OPENPIC_EVT_INT, 1); + if (priority < dst->raised.priority) { + /* An higher priority IRQ is already raised */ + DPRINTF("%s: IRQ %d is hidden by raised IRQ %d on CPU %d\n", + __func__, n_IRQ, dst->raised.next, n_CPU); + return; + } + IRQ_get_next(opp, &dst->raised); + if (IRQ_get_next(opp, &dst->servicing) != -1 && + priority < dst->servicing.priority) { + DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n", + __func__, n_IRQ, dst->servicing.next, n_CPU); + /* Already servicing a higher priority IRQ */ + return; } + DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", n_CPU, n_IRQ); + qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]); } /* update pic state because registers for n_IRQ have changed value */ @@ -280,27 +297,34 @@ static void openpic_update_irq(openpic_t *opp, int n_IRQ) if (!src->pending) { /* no irq pending */ + DPRINTF("%s: IRQ %d is not pending\n", __func__, n_IRQ); return; } if (test_bit(&src->ipvp, IPVP_MASK)) { /* Interrupt source is disabled */ + DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ); return; } if (IPVP_PRIORITY(src->ipvp) == 0) { /* Priority set to zero */ + DPRINTF("%s: IRQ %d has 0 priority\n", __func__, n_IRQ); return; } if (test_bit(&src->ipvp, IPVP_ACTIVITY)) { /* IRQ already active */ + DPRINTF("%s: IRQ %d is already active\n", __func__, n_IRQ); return; } if (src->ide == 0x00000000) { /* No target */ + DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ); return; } - if (!test_bit(&src->ipvp, IPVP_MODE) || - src->ide == (1 << src->last_cpu)) { + if (src->ide == (1 << src->last_cpu)) { + /* Only one CPU is allowed to receive this IRQ */ + IRQ_local_pipe(opp, src->last_cpu, n_IRQ); + } else if (!test_bit(&src->ipvp, IPVP_MODE)) { /* Directed delivery mode */ for (i = 0; i < opp->nb_cpus; i++) { if (test_bit(&src->ide, i)) @@ -308,9 +332,8 @@ static void openpic_update_irq(openpic_t *opp, int n_IRQ) } } else { /* Distributed delivery mode */ - /* XXX: incorrect code */ - for (i = src->last_cpu; i < src->last_cpu; i++) { - if (i == MAX_IRQ) + for (i = src->last_cpu + 1; i != src->last_cpu; i++) { + if (i == opp->nb_cpus) i = 0; if (test_bit(&src->ide, i)) { IRQ_local_pipe(opp, i, n_IRQ); @@ -350,6 +373,7 @@ static void openpic_reset (openpic_t *opp) /* Initialise controller registers */ opp->frep = ((EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID; opp->veni = VENI; + opp->pint = 0x00000000; opp->spve = 0x000000FF; opp->tifr = 0x003F7A00; /* ? */ @@ -360,7 +384,7 @@ static void openpic_reset (openpic_t *opp) opp->src[i].ide = 0x00000000; } /* Initialise IRQ destinations */ - for (i = 0; i < opp->nb_cpus; i++) { + for (i = 0; i < MAX_CPU; i++) { opp->dst[i].pctp = 0x0000000F; opp->dst[i].pcsr = 0x00000000; memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t)); @@ -511,6 +535,8 @@ static void write_mailbox_register (openpic_t *opp, int n_mbx, static void openpic_gbl_write (void *opaque, uint32_t addr, uint32_t val) { openpic_t *opp = opaque; + IRQ_dst_t *dst; + int idx; DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); if (addr & 0xF) @@ -530,11 +556,18 @@ static void openpic_gbl_write (void *opaque, uint32_t addr, uint32_t val) case 0x80: /* VENI */ break; case 0x90: /* PINT */ - /* XXX: Should be able to reset any CPU */ - if (val & 1) { - DPRINTF("Reset CPU IRQ\n"); - // opp->set_irq(dst->env, OPENPIC_EVT_RESET, 1); + for (idx = 0; idx < opp->nb_cpus; idx++) { + if ((val & (1 << idx)) && !(opp->pint & (1 << idx))) { + DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx); + dst = &opp->dst[idx]; + qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_RESET]); + } else if (!(val & (1 << idx)) && (opp->pint & (1 << idx))) { + DPRINTF("Lower OpenPIC RESET output for CPU %d\n", idx); + dst = &opp->dst[idx]; + qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_RESET]); + } } + opp->pint = val; break; #if MAX_IPI > 0 case 0xA0: /* IPI_IPVP */ @@ -735,7 +768,7 @@ static void openpic_cpu_write (void *opaque, uint32_t addr, uint32_t val) openpic_t *opp = opaque; IRQ_src_t *src; IRQ_dst_t *dst; - int idx, n_IRQ; + int idx, s_IRQ, n_IRQ; DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); if (addr & 0xF) @@ -770,21 +803,21 @@ static void openpic_cpu_write (void *opaque, uint32_t addr, uint32_t val) break; case 0xB0: /* PEOI */ DPRINTF("PEOI\n"); - n_IRQ = IRQ_get_next(opp, &dst->servicing); - IRQ_resetbit(&dst->servicing, n_IRQ); + s_IRQ = IRQ_get_next(opp, &dst->servicing); + IRQ_resetbit(&dst->servicing, s_IRQ); dst->servicing.next = -1; - src = &opp->src[n_IRQ]; /* Set up next servicing IRQ */ - IRQ_get_next(opp, &dst->servicing); - /* Check queued interrupts. */ - n_IRQ = IRQ_get_next(opp, &dst->raised); - if (n_IRQ != -1) { - src = &opp->src[n_IRQ]; - if (IPVP_PRIORITY(src->ipvp) > dst->servicing.priority) { - DPRINTF("Raise CPU IRQ\n"); - opp->set_irq(dst->env, OPENPIC_EVT_INT, 1); - } - } + s_IRQ = IRQ_get_next(opp, &dst->servicing); + /* Check queued interrupts. */ + n_IRQ = IRQ_get_next(opp, &dst->raised); + src = &opp->src[n_IRQ]; + if (n_IRQ != -1 && + (s_IRQ == -1 || + IPVP_PRIORITY(src->ipvp) > dst->servicing.priority)) { + DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", + idx, n_IRQ); + qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]); + } break; default: break; @@ -815,11 +848,13 @@ static uint32_t openpic_cpu_read (void *opaque, uint32_t addr) retval = idx; break; case 0xA0: /* PIAC */ + DPRINTF("Lower OpenPIC INT output\n"); + qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]); n_IRQ = IRQ_get_next(opp, &dst->raised); DPRINTF("PIAC: irq=%d\n", n_IRQ); if (n_IRQ == -1) { /* No more interrupt pending */ - retval = opp->spve; + retval = IPVP_VECTOR(opp->spve); } else { src = &opp->src[n_IRQ]; if (!test_bit(&src->ipvp, IPVP_ACTIVITY) || @@ -964,8 +999,8 @@ static void openpic_map(PCIDevice *pci_dev, int region_num, #endif } -qemu_irq *openpic_init (PCIBus *bus, SetIRQFunc *set_irq, - int *pmem_index, int nb_cpus, CPUState **envp) +qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus, + qemu_irq **irqs, qemu_irq irq_out) { openpic_t *opp; uint8_t *pci_conf; @@ -995,7 +1030,6 @@ qemu_irq *openpic_init (PCIBus *bus, SetIRQFunc *set_irq, } else { opp = qemu_mallocz(sizeof(openpic_t)); } - opp->set_irq = set_irq; opp->mem_index = cpu_register_io_memory(0, openpic_read, openpic_write, opp); @@ -1020,9 +1054,11 @@ qemu_irq *openpic_init (PCIBus *bus, SetIRQFunc *set_irq, opp->src[i].type = IRQ_INTERNAL; } for (i = 0; i < nb_cpus; i++) - opp->dst[i].env = envp[i]; + opp->dst[i].irqs = irqs[i]; + opp->irq_out = irq_out; openpic_reset(opp); if (pmem_index) *pmem_index = opp->mem_index; + return qemu_allocate_irqs(openpic_set_irq, opp, MAX_IRQ); } @@ -1,5 +1,5 @@ /* - * QEMU generic PPC hardware System Emulator + * QEMU generic PowerPC hardware System Emulator * * Copyright (c) 2003-2007 Jocelyn Mayer * @@ -24,18 +24,13 @@ #include "vl.h" #include "m48t59.h" +//#define PPC_DEBUG_IRQ + extern FILE *logfile; extern int loglevel; -/*****************************************************************************/ -/* PowerPC internal fake IRQ controller - * used to manage multiple sources hardware events - */ -static void ppc_set_irq (void *opaque, int n_IRQ, int level) +void ppc_set_irq (CPUState *env, int n_IRQ, int level) { - CPUState *env; - - env = opaque; if (level) { env->pending_interrupts |= 1 << n_IRQ; cpu_interrupt(env, CPU_INTERRUPT_HARD); @@ -44,49 +39,104 @@ static void ppc_set_irq (void *opaque, int n_IRQ, int level) if (env->pending_interrupts == 0) cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); } -#if 0 +#if defined(PPC_DEBUG_IRQ) printf("%s: %p n_IRQ %d level %d => pending %08x req %08x\n", __func__, env, n_IRQ, level, env->pending_interrupts, env->interrupt_request); #endif } -void cpu_ppc_irq_init_cpu(CPUState *env) +/* PowerPC 6xx / 7xx internal IRQ controller */ +static void ppc6xx_set_irq (void *opaque, int pin, int level) { - qemu_irq *qi; - int i; + CPUState *env = opaque; + int cur_level; - qi = qemu_allocate_irqs(ppc_set_irq, env, 32); - for (i = 0; i < 32; i++) { - env->irq[i] = qi[i]; +#if defined(PPC_DEBUG_IRQ) + printf("%s: env %p pin %d level %d\n", __func__, env, pin, level); +#endif + cur_level = (env->irq_input_state >> pin) & 1; + /* Don't generate spurious events */ + if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0) || 0) { + switch (pin) { + case PPC_INPUT_INT: + /* Level sensitive - asserted high */ +#if defined(PPC_DEBUG_IRQ) + printf("%s: set the external IRQ state to %d\n", __func__, level); +#endif + ppc_set_irq(env, PPC_INTERRUPT_EXT, level); + break; + case PPC_INPUT_SMI: + /* Level sensitive - active high */ +#if defined(PPC_DEBUG_IRQ) + printf("%s: set the SMI IRQ state to %d\n", __func__, level); +#endif + ppc_set_irq(env, PPC_INTERRUPT_SMI, level); + break; + case PPC_INPUT_MCP: + /* Negative edge sensitive */ + /* XXX: TODO: actual reaction may depends on HID0 status + * 603/604/740/750: check HID0[EMCP] + */ + if (cur_level == 1 && level == 0) { +#if defined(PPC_DEBUG_IRQ) + printf("%s: raise machine check state\n", __func__); +#endif + ppc_set_irq(env, PPC_INTERRUPT_MCK, 1); + } + break; + case PPC_INPUT_CKSTP_IN: + /* Level sensitive - active low */ + /* XXX: TODO: relay the signal to CKSTP_OUT pin */ + if (level) { +#if defined(PPC_DEBUG_IRQ) + printf("%s: stop the CPU\n", __func__); +#endif + env->halted = 1; + } else { +#if defined(PPC_DEBUG_IRQ) + printf("%s: restart the CPU\n", __func__); +#endif + env->halted = 0; + } + break; + case PPC_INPUT_HRESET: + /* Level sensitive - active low */ + if (level) { +#if 0 // XXX: TOFIX +#if defined(PPC_DEBUG_IRQ) + printf("%s: reset the CPU\n", __func__); +#endif + cpu_reset(env); +#endif + } + break; + case PPC_INPUT_SRESET: +#if defined(PPC_DEBUG_IRQ) + printf("%s: set the RESET IRQ state to %d\n", __func__, level); +#endif + ppc_set_irq(env, PPC_INTERRUPT_RESET, level); + break; + default: + /* Unknown pin - do nothing */ +#if defined(PPC_DEBUG_IRQ) + printf("%s: unknown IRQ pin %d\n", __func__, pin); +#endif + return; + } + if (level) + env->irq_input_state |= 1 << pin; + else + env->irq_input_state &= ~(1 << pin); } } -/* External IRQ callback from OpenPIC IRQ controller */ -void ppc_openpic_irq (void *opaque, int n_IRQ, int level) +void ppc6xx_irq_init (CPUState *env) { - switch (n_IRQ) { - case OPENPIC_EVT_INT: - n_IRQ = PPC_INTERRUPT_EXT; - break; - case OPENPIC_EVT_CINT: - /* On PowerPC BookE, critical input use vector 0 */ - n_IRQ = PPC_INTERRUPT_RESET; - break; - case OPENPIC_EVT_MCK: - n_IRQ = PPC_INTERRUPT_MCK; - break; - case OPENPIC_EVT_DEBUG: - n_IRQ = PPC_INTERRUPT_DEBUG; - break; - case OPENPIC_EVT_RESET: - qemu_system_reset_request(); - return; - } - ppc_set_irq(opaque, n_IRQ, level); + env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, env, 6); } /*****************************************************************************/ -/* PPC time base and decrementer emulation */ +/* PowerPC time base and decrementer emulation */ //#define DEBUG_TB struct ppc_tb_t { diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index 18a1aab2b5..c418cd1b4a 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -23,6 +23,9 @@ */ #include "vl.h" +/* SMP is not enabled, for now */ +#define MAX_CPUS 1 + #define BIOS_FILENAME "ppc_rom.bin" #define VGABIOS_FILENAME "video.x" #define NVRAM_SIZE 0x2000 @@ -296,9 +299,9 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, const char *cpu_model, int is_heathrow) { - CPUState *env; + CPUState *env, *envs[MAX_CPUS]; char buf[1024]; - qemu_irq *pic; + qemu_irq *pic, **openpic_irqs; m48t59_t *nvram; int unin_memory; int linux_boot, i; @@ -329,13 +332,13 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, if (def == NULL) { cpu_abort(env, "Unable to find PowerPC CPU definition\n"); } - cpu_ppc_register(env, def); - cpu_ppc_irq_init_cpu(env); - - /* Set time-base frequency to 100 Mhz */ - cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL); - - env->osi_call = vga_osi_call; + for (i = 0; i < smp_cpus; i++) { + cpu_ppc_register(env, def); + /* Set time-base frequency to 100 Mhz */ + cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL); + env->osi_call = vga_osi_call; + envs[i] = env; + } /* allocate RAM */ cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); @@ -458,7 +461,26 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, unin_memory = cpu_register_io_memory(0, unin_read, unin_write, NULL); cpu_register_physical_memory(0xf8000000, 0x00001000, unin_memory); - pic = openpic_init(NULL, &ppc_openpic_irq, &openpic_mem_index, 1, &env); + openpic_irqs = qemu_mallocz(smp_cpus * sizeof(qemu_irq *)); + openpic_irqs[0] = + qemu_mallocz(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB); + for (i = 0; i < smp_cpus; i++) { + /* Mac99 IRQ connection between OpenPIC outputs pins + * and PowerPC input pins + */ + openpic_irqs[i] = openpic_irqs[0] + (i * OPENPIC_OUTPUT_NB); + openpic_irqs[i][OPENPIC_OUTPUT_INT] = + ((qemu_irq *)env->irq_inputs)[PPC_INPUT_INT]; + openpic_irqs[i][OPENPIC_OUTPUT_CINT] = + ((qemu_irq *)env->irq_inputs)[PPC_INPUT_INT]; + openpic_irqs[i][OPENPIC_OUTPUT_MCK] = + ((qemu_irq *)env->irq_inputs)[PPC_INPUT_MCP]; + openpic_irqs[i][OPENPIC_OUTPUT_DEBUG] = NULL; /* Not connected ? */ + openpic_irqs[i][OPENPIC_OUTPUT_RESET] = + ((qemu_irq *)env->irq_inputs)[PPC_INPUT_HRESET]; /* Check this */ + } + pic = openpic_init(NULL, &openpic_mem_index, smp_cpus, + openpic_irqs, NULL); pci_bus = pci_pmac_init(pic); /* init basic PC hardware */ pci_vga_init(pci_bus, ds, phys_ram_base + ram_size, diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 225b531685..8b53ef30a8 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -548,7 +548,6 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, cpu_abort(env, "Unable to find PowerPC CPU definition\n"); } cpu_ppc_register(env, def); - cpu_ppc_irq_init_cpu(env); /* Set time-base frequency to 100 Mhz */ cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL); @@ -599,7 +598,7 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, } isa_mem_base = 0xc0000000; - i8259 = i8259_init(first_cpu->irq[PPC_INTERRUPT_EXT]); + i8259 = i8259_init(first_cpu->irq_inputs[PPC_INPUT_INT]); pci_bus = pci_prep_init(i8259); // pci_bus = i440fx_init(); /* Register 8 MB of ISA IO space (needed for non-contiguous map) */ diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 1515af9930..0560a38a1e 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -758,7 +758,13 @@ struct CPUPPCState { int error_code; int interrupt_request; uint32_t pending_interrupts; - void *irq[32]; +#if !defined(CONFIG_USER_ONLY) + /* This is the IRQ controller, which is implementation dependant + * and only relevant when emulating a complete machine. + */ + uint32_t irq_input_state; + void **irq_inputs; +#endif /* Those resources are used only during code translation */ /* Next instruction pointer */ @@ -801,6 +807,7 @@ int cpu_ppc_signal_handler(int host_signum, void *pinfo, void *puc); void do_interrupt (CPUPPCState *env); +void ppc_hw_interrupt (CPUPPCState *env); void cpu_loop_exit(void); void dump_stack (CPUPPCState *env); @@ -1303,16 +1310,35 @@ enum { /* Hardware interruption sources: * all those exception can be raised simulteaneously */ +/* Input pins definitions */ +enum { + /* 6xx bus input pins */ + PPC_INPUT_HRESET = 0, + PPC_INPUT_SRESET = 1, + PPC_INPUT_CKSTP_IN = 2, + PPC_INPUT_MCP = 3, + PPC_INPUT_SMI = 4, + PPC_INPUT_INT = 5, + /* Embedded PowerPC input pins */ + PPC_INPUT_CINT = 6, + PPC_INPUT_NB, +}; + +/* Hardware exceptions definitions */ enum { - PPC_INTERRUPT_RESET = 0, /* Reset / critical input */ - PPC_INTERRUPT_MCK = 1, /* Machine check exception */ - PPC_INTERRUPT_EXT = 2, /* External interrupt */ - PPC_INTERRUPT_DECR = 3, /* Decrementer exception */ - PPC_INTERRUPT_HDECR = 4, /* Hypervisor decrementer exception */ - PPC_INTERRUPT_PIT = 5, /* Programmable inteval timer interrupt */ - PPC_INTERRUPT_FIT = 6, /* Fixed interval timer interrupt */ - PPC_INTERRUPT_WDT = 7, /* Watchdog timer interrupt */ - PPC_INTERRUPT_DEBUG = 8, /* External debug exception */ + /* External hardware exception sources */ + PPC_INTERRUPT_RESET = 0, /* Reset exception */ + PPC_INTERRUPT_MCK = 1, /* Machine check exception */ + PPC_INTERRUPT_EXT = 2, /* External interrupt */ + PPC_INTERRUPT_SMI = 3, /* System management interrupt */ + PPC_INTERRUPT_CEXT = 4, /* Critical external interrupt */ + PPC_INTERRUPT_DEBUG = 5, /* External debug exception */ + /* Internal hardware exception sources */ + PPC_INTERRUPT_DECR = 6, /* Decrementer exception */ + PPC_INTERRUPT_HDECR = 7, /* Hypervisor decrementer exception */ + PPC_INTERRUPT_PIT = 8, /* Programmable inteval timer interrupt */ + PPC_INTERRUPT_FIT = 9, /* Fixed interval timer interrupt */ + PPC_INTERRUPT_WDT = 10, /* Watchdog timer interrupt */ }; /*****************************************************************************/ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 69ed260f75..b9a55b1f2b 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -1358,11 +1358,9 @@ void do_interrupt (CPUState *env) env->exception_index = -1; } -int ppc_hw_interrupt (CPUState *env) +void ppc_hw_interrupt (CPUState *env) { env->exception_index = -1; - - return 0; } #else /* defined (CONFIG_USER_ONLY) */ static void dump_syscall(CPUState *env) @@ -1927,7 +1925,7 @@ void do_interrupt (CPUState *env) env->exception_index = EXCP_NONE; } -int ppc_hw_interrupt (CPUState *env) +void ppc_hw_interrupt (CPUPPCState *env) { int raised = 0; @@ -1940,6 +1938,9 @@ int ppc_hw_interrupt (CPUState *env) /* Raise it */ if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) { /* External reset / critical input */ + /* XXX: critical input should be handled another way. + * This code is not correct ! + */ env->exception_index = EXCP_RESET; env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET); raised = 1; @@ -1984,7 +1985,12 @@ int ppc_hw_interrupt (CPUState *env) /* External interrupt */ } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) { env->exception_index = EXCP_EXTERNAL; + /* Taking an external interrupt does not clear the external + * interrupt status + */ +#if 0 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT); +#endif raised = 1; } #if 0 // TODO @@ -1999,7 +2005,5 @@ int ppc_hw_interrupt (CPUState *env) env->error_code = 0; do_interrupt(env); } - - return raised; } #endif /* !CONFIG_USER_ONLY */ diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index d5626316c9..805c897248 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -35,6 +35,18 @@ struct ppc_def_t { uint64_t msr_mask; }; +/* For user-mode emulation, we don't emulate any IRQ controller */ +#if defined(CONFIG_USER_ONLY) +#define PPC_IRQ_INIT_FN(name) \ +static inline void glue(glue(ppc, name),_irq_init) (CPUPPCState *env) \ +{ \ +} +#else +#define PPC_IRQ_INIT_FN(name) \ +void glue(glue(ppc, name),_irq_init) (CPUPPCState *env); +#endif +PPC_IRQ_INIT_FN(6xx); + /* Generic callbacks: * do nothing but store/retrieve spr value */ @@ -1865,6 +1877,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + /* XXX: TODO: allocate internal IRQ controller */ break; case CPU_PPC_403GA: /* 403 GA family */ @@ -1879,6 +1892,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + /* XXX: TODO: allocate internal IRQ controller */ break; case CPU_PPC_405CR: /* 405 GP/CR family */ @@ -1895,6 +1909,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + /* XXX: TODO: allocate internal IRQ controller */ break; case CPU_PPC_NPE405H: /* NPe405 H family */ @@ -1909,6 +1924,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + /* XXX: TODO: allocate internal IRQ controller */ break; #if defined (TODO) @@ -1940,6 +1956,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + /* XXX: TODO: allocate internal IRQ controller */ break; case CPU_PPC_440EP: /* 440 EP family */ @@ -1959,6 +1976,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + /* XXX: TODO: allocate internal IRQ controller */ break; /* Embedded PowerPC from Freescale */ @@ -1994,6 +2012,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + /* XXX: TODO: allocate internal IRQ controller */ break; #if defined (TODO) @@ -2038,6 +2057,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) env->nb_ways = 2; env->id_tlbs = 0; env->id_tlbs = 0; + /* XXX: TODO: allocate internal IRQ controller */ break; case CPU_PPC_602: /* PowerPC 602 */ @@ -2060,6 +2080,8 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); break; case CPU_PPC_603: /* PowerPC 603 */ @@ -2087,6 +2109,8 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); break; case CPU_PPC_G2: /* PowerPC G2 family */ @@ -2123,6 +2147,8 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); break; case CPU_PPC_604: /* PowerPC 604 */ @@ -2146,6 +2172,8 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); break; case CPU_PPC_74x: /* PowerPC 740 / 750 */ @@ -2178,6 +2206,8 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); break; case CPU_PPC_750FX10: /* IBM PowerPC 750 FX */ @@ -2213,6 +2243,8 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); break; case CPU_PPC_755_10: /* PowerPC 755 */ @@ -2257,6 +2289,8 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); break; #if defined (TODO) @@ -2326,6 +2360,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) default: gen_spr_generic(env); + /* XXX: TODO: allocate internal IRQ controller */ break; } if (env->nb_BATs == -1) @@ -854,16 +854,17 @@ void i440fx_init_memory_mappings(PCIDevice *d); int piix4_init(PCIBus *bus, int devfn); /* openpic.c */ +/* OpenPIC have 5 outputs per CPU connected and one IRQ out single output */ enum { - OPENPIC_EVT_INT = 0, /* IRQ */ - OPENPIC_EVT_CINT, /* critical IRQ */ - OPENPIC_EVT_MCK, /* Machine check event */ - OPENPIC_EVT_DEBUG, /* Inconditional debug event */ - OPENPIC_EVT_RESET, /* Core reset event */ + OPENPIC_OUTPUT_INT = 0, /* IRQ */ + OPENPIC_OUTPUT_CINT, /* critical IRQ */ + OPENPIC_OUTPUT_MCK, /* Machine check event */ + OPENPIC_OUTPUT_DEBUG, /* Inconditional debug event */ + OPENPIC_OUTPUT_RESET, /* Core reset event */ + OPENPIC_OUTPUT_NB, }; -qemu_irq *openpic_init (PCIBus *bus, SetIRQFunc *set_irq, - int *pmem_index, int nb_cpus, - struct CPUState **envp); +qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus, + qemu_irq **irqs, qemu_irq irq_out); /* heathrow_pic.c */ qemu_irq *heathrow_pic_init(int *pmem_index); @@ -1145,9 +1146,6 @@ extern QEMUMachine shix_machine; #ifdef TARGET_PPC /* PowerPC hardware exceptions management helpers */ -void cpu_ppc_irq_init_cpu(CPUState *env); -void ppc_openpic_irq (void *opaque, int n_IRQ, int level); -int ppc_hw_interrupt (CPUState *env); ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq); #endif void PREP_debug_write (void *opaque, uint32_t addr, uint32_t val); |