Commit 471035729088e3aa7f69140ac0ad0b248ff7ec07

Authored by j_mayer
1 parent de270b3c

New model for PowerPC CPU hardware interrupt events:

move all PowerPC specific code into target-ppc/helper.c to avoid polluting
the common code in cpu-exec.c. This makes implementation of new features
(ie embedded PowerPC timers, critical interrupts, ...) easier.
This also avoid hardcoding the IRQ callback in the OpenPIC controller,
making it more easily reusable and allowing cascading.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2542 c046a42c-6fe2-441c-8c8c-71466251a162
cpu-exec.c
... ... @@ -256,8 +256,7 @@ int cpu_exec(CPUState *env1)
256 256 #elif defined(TARGET_PPC)
257 257 if (env1->halted) {
258 258 if (env1->msr[MSR_EE] &&
259   - (env1->interrupt_request &
260   - (CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER))) {
  259 + (env1->interrupt_request & CPU_INTERRUPT_HARD)) {
261 260 env1->halted = 0;
262 261 } else {
263 262 return EXCP_HALTED;
... ... @@ -448,24 +447,11 @@ int cpu_exec(CPUState *env1)
448 447 cpu_ppc_reset(env);
449 448 }
450 449 #endif
451   - if (msr_ee != 0) {
452   - if ((interrupt_request & CPU_INTERRUPT_HARD)) {
453   - /* Raise it */
454   - env->exception_index = EXCP_EXTERNAL;
455   - env->error_code = 0;
456   - do_interrupt(env);
457   - env->interrupt_request &= ~CPU_INTERRUPT_HARD;
458   -#if defined(__sparc__) && !defined(HOST_SOLARIS)
459   - tmp_T0 = 0;
460   -#else
461   - T0 = 0;
462   -#endif
463   - } else if ((interrupt_request & CPU_INTERRUPT_TIMER)) {
464   - /* Raise it */
465   - env->exception_index = EXCP_DECR;
466   - env->error_code = 0;
467   - do_interrupt(env);
468   - env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
  450 + if (interrupt_request & CPU_INTERRUPT_HARD) {
  451 + if (ppc_hw_interrupt(env) == 1) {
  452 + /* Some exception was raised */
  453 + if (env->pending_interrupts == 0)
  454 + env->interrupt_request &= ~CPU_INTERRUPT_HARD;
469 455 #if defined(__sparc__) && !defined(HOST_SOLARIS)
470 456 tmp_T0 = 0;
471 457 #else
... ...
hw/openpic.c
... ... @@ -164,6 +164,7 @@ typedef struct IRQ_dst_t {
164 164  
165 165 struct openpic_t {
166 166 PCIDevice pci_dev;
  167 + SetIRQFunc *set_irq;
167 168 int mem_index;
168 169 /* Global registers */
169 170 uint32_t frep; /* Feature reporting register */
... ... @@ -264,8 +265,8 @@ static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ)
264 265 IRQ_setbit(&dst->raised, n_IRQ);
265 266 if (priority > dst->raised.priority) {
266 267 IRQ_get_next(opp, &dst->raised);
267   - DPRINTF("Raise CPU IRQ\n");
268   - cpu_interrupt(dst->env, CPU_INTERRUPT_HARD);
  268 + DPRINTF("Raise CPU IRQ fn %p env %p\n", opp->set_irq, dst->env);
  269 + opp->set_irq(dst->env, OPENPIC_EVT_INT, 1);
269 270 }
270 271 }
271 272  
... ... @@ -532,7 +533,7 @@ static void openpic_gbl_write (void *opaque, uint32_t addr, uint32_t val)
532 533 /* XXX: Should be able to reset any CPU */
533 534 if (val & 1) {
534 535 DPRINTF("Reset CPU IRQ\n");
535   - // cpu_interrupt(first_cpu, CPU_INTERRUPT_RESET);
  536 + // opp->set_irq(dst->env, OPENPIC_EVT_RESET, 1);
536 537 }
537 538 break;
538 539 #if MAX_IPI > 0
... ... @@ -781,7 +782,7 @@ static void openpic_cpu_write (void *opaque, uint32_t addr, uint32_t val)
781 782 src = &opp->src[n_IRQ];
782 783 if (IPVP_PRIORITY(src->ipvp) > dst->servicing.priority) {
783 784 DPRINTF("Raise CPU IRQ\n");
784   - cpu_interrupt(dst->env, CPU_INTERRUPT_HARD);
  785 + opp->set_irq(dst->env, OPENPIC_EVT_INT, 1);
785 786 }
786 787 }
787 788 break;
... ... @@ -963,8 +964,8 @@ static void openpic_map(PCIDevice *pci_dev, int region_num,
963 964 #endif
964 965 }
965 966  
966   -openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
967   - CPUPPCState **envp)
  967 +openpic_t *openpic_init (PCIBus *bus, SetIRQFunc *set_irq,
  968 + int *pmem_index, int nb_cpus, CPUPPCState **envp)
968 969 {
969 970 openpic_t *opp;
970 971 uint8_t *pci_conf;
... ... @@ -994,7 +995,7 @@ openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
994 995 } else {
995 996 opp = qemu_mallocz(sizeof(openpic_t));
996 997 }
997   -
  998 + opp->set_irq = set_irq;
998 999 opp->mem_index = cpu_register_io_memory(0, openpic_read,
999 1000 openpic_write, opp);
1000 1001  
... ...
hw/ppc.c
... ... @@ -24,6 +24,57 @@
24 24 #include "vl.h"
25 25 #include "m48t59.h"
26 26  
  27 +extern FILE *logfile;
  28 +extern int loglevel;
  29 +
  30 +/*****************************************************************************/
  31 +/* PowerPC internal fake IRQ controller
  32 + * used to manage multiple sources hardware events
  33 + */
  34 +/* XXX: should be protected */
  35 +void ppc_set_irq (void *opaque, int n_IRQ, int level)
  36 +{
  37 + CPUState *env;
  38 +
  39 + env = opaque;
  40 + if (level) {
  41 + env->pending_interrupts |= 1 << n_IRQ;
  42 + cpu_interrupt(env, CPU_INTERRUPT_HARD);
  43 + } else {
  44 + env->pending_interrupts &= ~(1 << n_IRQ);
  45 + if (env->pending_interrupts == 0)
  46 + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
  47 + }
  48 +#if 0
  49 + printf("%s: %p n_IRQ %d level %d => pending %08x req %08x\n", __func__,
  50 + env, n_IRQ, level, env->pending_interrupts, env->interrupt_request);
  51 +#endif
  52 +}
  53 +
  54 +/* External IRQ callback from OpenPIC IRQ controller */
  55 +void ppc_openpic_irq (void *opaque, int n_IRQ, int level)
  56 +{
  57 + switch (n_IRQ) {
  58 + case OPENPIC_EVT_INT:
  59 + n_IRQ = PPC_INTERRUPT_EXT;
  60 + break;
  61 + case OPENPIC_EVT_CINT:
  62 + /* On PowerPC BookE, critical input use vector 0 */
  63 + n_IRQ = PPC_INTERRUPT_RESET;
  64 + break;
  65 + case OPENPIC_EVT_MCK:
  66 + n_IRQ = PPC_INTERRUPT_MCK;
  67 + break;
  68 + case OPENPIC_EVT_DEBUG:
  69 + n_IRQ = PPC_INTERRUPT_DEBUG;
  70 + break;
  71 + case OPENPIC_EVT_RESET:
  72 + qemu_system_reset_request();
  73 + return;
  74 + }
  75 + ppc_set_irq(opaque, n_IRQ, level);
  76 +}
  77 +
27 78 /*****************************************************************************/
28 79 /* PPC time base and decrementer emulation */
29 80 //#define DEBUG_TB
... ... @@ -35,6 +86,7 @@ struct ppc_tb_t {
35 86 /* Decrementer management */
36 87 uint64_t decr_next; /* Tick for next decr interrupt */
37 88 struct QEMUTimer *decr_timer;
  89 + void *opaque;
38 90 };
39 91  
40 92 static inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env)
... ... @@ -131,7 +183,7 @@ static inline void cpu_ppc_decr_excp (CPUState *env)
131 183 #ifdef DEBUG_TB
132 184 printf("raise decrementer exception\n");
133 185 #endif
134   - cpu_interrupt(env, CPU_INTERRUPT_TIMER);
  186 + ppc_set_irq(env, PPC_INTERRUPT_DECR, 1);
135 187 }
136 188  
137 189 static void _cpu_ppc_store_decr (CPUState *env, uint32_t decr,
... ...
hw/ppc_chrp.c
1 1 /*
2 2 * QEMU PPC CHRP/PMAC hardware System Emulator
3 3 *
4   - * Copyright (c) 2004 Fabrice Bellard
  4 + * Copyright (c) 2004-2007 Fabrice Bellard
5 5 *
6 6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 7 * of this software and associated documentation files (the "Software"), to deal
... ... @@ -449,21 +449,21 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device,
449 449 }
450 450  
451 451 macio_init(pci_bus, 0x0017);
452   -
  452 +
453 453 nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE, 59);
454   -
  454 +
455 455 arch_name = "HEATHROW";
456 456 } else {
457 457 isa_mem_base = 0x80000000;
458   -
  458 +
459 459 /* Register 8 MB of ISA IO space */
460 460 isa_mmio_init(0xf2000000, 0x00800000);
461   -
  461 +
462 462 /* UniN init */
463 463 unin_memory = cpu_register_io_memory(0, unin_read, unin_write, NULL);
464 464 cpu_register_physical_memory(0xf8000000, 0x00001000, unin_memory);
465 465  
466   - pic = openpic_init(NULL, &openpic_mem_index, 1, &env);
  466 + pic = openpic_init(NULL, &ppc_openpic_irq, &openpic_mem_index, 1, &env);
467 467 set_irq = openpic_set_irq;
468 468 pci_bus = pci_pmac_init(pic);
469 469 /* init basic PC hardware */
... ...
hw/ppc_prep.c
1 1 /*
2 2 * QEMU PPC PREP hardware System Emulator
3 3 *
4   - * Copyright (c) 2003-2004 Jocelyn Mayer
  4 + * Copyright (c) 2003-2007 Jocelyn Mayer
5 5 *
6 6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 7 * of this software and associated documentation files (the "Software"), to deal
... ... @@ -84,29 +84,27 @@ static void speaker_ioport_write(void *opaque, uint32_t addr, uint32_t val)
84 84 #endif
85 85 }
86 86  
87   -static uint32_t speaker_ioport_read(void *opaque, uint32_t addr)
  87 +static uint32_t speaker_ioport_read (void *opaque, uint32_t addr)
88 88 {
89 89 #if 0
90 90 int out;
91 91 out = pit_get_out(pit, 2, qemu_get_clock(vm_clock));
92 92 dummy_refresh_clock ^= 1;
93 93 return (speaker_data_on << 1) | pit_get_gate(pit, 2) | (out << 5) |
94   - (dummy_refresh_clock << 4);
  94 + (dummy_refresh_clock << 4);
95 95 #endif
96 96 return 0;
97 97 }
98 98  
99   -static void pic_irq_request(void *opaque, int level)
  99 +static void pic_irq_request (void *opaque, int level)
100 100 {
101   - if (level)
102   - cpu_interrupt(first_cpu, CPU_INTERRUPT_HARD);
103   - else
104   - cpu_reset_interrupt(first_cpu, CPU_INTERRUPT_HARD);
  101 + ppc_set_irq(opaque, PPC_INTERRUPT_EXT, level);
105 102 }
106 103  
107 104 /* PCI intack register */
108 105 /* Read-only register (?) */
109   -static void _PPC_intack_write (void *opaque, target_phys_addr_t addr, uint32_t value)
  106 +static void _PPC_intack_write (void *opaque,
  107 + target_phys_addr_t addr, uint32_t value)
110 108 {
111 109 // printf("%s: 0x%08x => 0x%08x\n", __func__, addr, value);
112 110 }
... ... @@ -294,7 +292,7 @@ static void PREP_io_800_writeb (void *opaque, uint32_t addr, uint32_t val)
294 292 /* Special port 92 */
295 293 /* Check soft reset asked */
296 294 if (val & 0x01) {
297   - // cpu_interrupt(first_cpu, CPU_INTERRUPT_RESET);
  295 + // cpu_interrupt(first_cpu, PPC_INTERRUPT_RESET);
298 296 }
299 297 /* Check LE mode */
300 298 if (val & 0x02) {
... ...
target-ppc/cpu.h
... ... @@ -740,6 +740,7 @@ struct CPUPPCState {
740 740 int exception_index;
741 741 int error_code;
742 742 int interrupt_request;
  743 + uint32_t pending_interrupts;
743 744  
744 745 /* Those resources are used only during code translation */
745 746 /* Next instruction pointer */
... ... @@ -1267,6 +1268,21 @@ enum {
1267 1268 EXCP_TRAP = 0x40,
1268 1269 };
1269 1270  
  1271 +/* Hardware interruption sources:
  1272 + * all those exception can be raised simulteaneously
  1273 + */
  1274 +enum {
  1275 + PPC_INTERRUPT_RESET = 0, /* Reset / critical input */
  1276 + PPC_INTERRUPT_MCK = 1, /* Machine check exception */
  1277 + PPC_INTERRUPT_EXT = 2, /* External interrupt */
  1278 + PPC_INTERRUPT_DECR = 3, /* Decrementer exception */
  1279 + PPC_INTERRUPT_HDECR = 4, /* Hypervisor decrementer exception */
  1280 + PPC_INTERRUPT_PIT = 5, /* Programmable inteval timer interrupt */
  1281 + PPC_INTERRUPT_FIT = 6, /* Fixed interval timer interrupt */
  1282 + PPC_INTERRUPT_WDT = 7, /* Watchdog timer interrupt */
  1283 + PPC_INTERRUPT_DEBUG = 8, /* External debug exception */
  1284 +};
  1285 +
1270 1286 /*****************************************************************************/
1271 1287  
1272 1288 #endif /* !defined (__CPU_PPC_H__) */
... ...
target-ppc/helper.c
... ... @@ -1229,6 +1229,13 @@ void do_interrupt (CPUState *env)
1229 1229 {
1230 1230 env->exception_index = -1;
1231 1231 }
  1232 +
  1233 +int ppc_hw_interrupt (CPUState *env)
  1234 +{
  1235 + env->exception_index = -1;
  1236 +
  1237 + return 0;
  1238 +}
1232 1239 #else /* defined (CONFIG_USER_ONLY) */
1233 1240 static void dump_syscall(CPUState *env)
1234 1241 {
... ... @@ -1753,4 +1760,80 @@ void do_interrupt (CPUState *env)
1753 1760 env->nip = excp;
1754 1761 env->exception_index = EXCP_NONE;
1755 1762 }
  1763 +
  1764 +int ppc_hw_interrupt (CPUState *env)
  1765 +{
  1766 + int raised = 0;
  1767 +
  1768 +#if 0
  1769 + printf("%s: %p pending %08x req %08x %08x me %d ee %d\n",
  1770 + __func__, env, env->pending_interrupts,
  1771 + env->interrupt_request, interrupt_request,
  1772 + msr_me, msr_ee);
  1773 +#endif
  1774 + /* Raise it */
  1775 + if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
  1776 + /* External reset / critical input */
  1777 + env->exception_index = EXCP_RESET;
  1778 + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
  1779 + raised = 1;
  1780 + }
  1781 + if (raised == 0 && msr_me != 0) {
  1782 + /* Machine check exception */
  1783 + if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
  1784 + env->exception_index = EXCP_MACHINE_CHECK;
  1785 + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
  1786 + raised = 1;
  1787 + }
  1788 + }
  1789 + if (raised == 0 && msr_ee != 0) {
  1790 +#if defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */
  1791 + /* Hypervisor decrementer exception */
  1792 + if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) {
  1793 + env->exception_index = EXCP_HDECR;
  1794 + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
  1795 + raised = 1;
  1796 + } else
  1797 +#endif
  1798 + /* Decrementer exception */
  1799 + if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) {
  1800 + env->exception_index = EXCP_DECR;
  1801 + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
  1802 + raised = 1;
  1803 + /* Programmable interval timer on embedded PowerPC */
  1804 + } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
  1805 + env->exception_index = EXCP_40x_PIT;
  1806 + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
  1807 + raised = 1;
  1808 + /* Fixed interval timer on embedded PowerPC */
  1809 + } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
  1810 + env->exception_index = EXCP_40x_FIT;
  1811 + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
  1812 + raised = 1;
  1813 + /* Watchdog timer on embedded PowerPC */
  1814 + } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
  1815 + env->exception_index = EXCP_40x_WATCHDOG;
  1816 + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
  1817 + raised = 1;
  1818 + /* External interrupt */
  1819 + } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
  1820 + env->exception_index = EXCP_EXTERNAL;
  1821 + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT);
  1822 + raised = 1;
  1823 + }
  1824 +#if 0 // TODO
  1825 + /* External debug exception */
  1826 + } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
  1827 + env->exception_index = EXCP_xxx;
  1828 + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
  1829 + raised = 1;
  1830 +#endif
  1831 + }
  1832 + if (raised != 0) {
  1833 + env->error_code = 0;
  1834 + do_interrupt(env);
  1835 + }
  1836 +
  1837 + return raised;
  1838 +}
1756 1839 #endif /* !CONFIG_USER_ONLY */
... ...
... ... @@ -852,9 +852,16 @@ int piix4_init(PCIBus *bus, int devfn);
852 852  
853 853 /* openpic.c */
854 854 typedef struct openpic_t openpic_t;
  855 +enum {
  856 + OPENPIC_EVT_INT = 0, /* IRQ */
  857 + OPENPIC_EVT_CINT, /* critical IRQ */
  858 + OPENPIC_EVT_MCK, /* Machine check event */
  859 + OPENPIC_EVT_DEBUG, /* Inconditional debug event */
  860 + OPENPIC_EVT_RESET, /* Core reset event */
  861 +};
855 862 void openpic_set_irq(void *opaque, int n_IRQ, int level);
856   -openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
857   - CPUState **envp);
  863 +openpic_t *openpic_init (PCIBus *bus, SetIRQFunc *set_irq,
  864 + int *pmem_index, int nb_cpus, CPUPPCState **envp);
858 865  
859 866 /* heathrow_pic.c */
860 867 typedef struct HeathrowPICS HeathrowPICS;
... ... @@ -1115,6 +1122,10 @@ extern void cpu_mips_irqctrl_init (void);
1115 1122 extern QEMUMachine shix_machine;
1116 1123  
1117 1124 #ifdef TARGET_PPC
  1125 +/* PowerPC hardware exceptions management helpers */
  1126 +void ppc_set_irq (void *opaque, int n_IRQ, int level);
  1127 +void ppc_openpic_irq (void *opaque, int n_IRQ, int level);
  1128 +int ppc_hw_interrupt (CPUState *env);
1118 1129 ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq);
1119 1130 #endif
1120 1131 void PREP_debug_write (void *opaque, uint32_t addr, uint32_t val);
... ...