Revision 47103572
b/cpu-exec.c | ||
---|---|---|
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 | 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 |
b/hw/openpic.c | ||
---|---|---|
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 | 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 | 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 | 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 | 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 | 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 |
|
b/hw/ppc.c | ||
---|---|---|
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 | 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 | 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, |
b/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 | 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 */ |
b/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 | 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 | 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) { |
b/target-ppc/cpu.h | ||
---|---|---|
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 | 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__) */ |
b/target-ppc/helper.c | ||
---|---|---|
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 | 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 */ |
b/vl.h | ||
---|---|---|
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 | 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); |
Also available in: Unified diff