]> git.proxmox.com Git - qemu.git/blob - target-ppc/excp_helper.c
ppc: Avoid AREG0 for exception helpers
[qemu.git] / target-ppc / excp_helper.c
1 /*
2 * PowerPC exception emulation helpers for QEMU.
3 *
4 * Copyright (c) 2003-2007 Jocelyn Mayer
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19 #include "cpu.h"
20 #include "helper.h"
21
22 #include "helper_regs.h"
23
24 //#define DEBUG_OP
25 //#define DEBUG_EXCEPTIONS
26
27 /*****************************************************************************/
28 /* Exceptions processing helpers */
29
30 void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
31 uint32_t error_code)
32 {
33 #if 0
34 printf("Raise exception %3x code : %d\n", exception, error_code);
35 #endif
36 env->exception_index = exception;
37 env->error_code = error_code;
38 cpu_loop_exit(env);
39 }
40
41 void helper_raise_exception(CPUPPCState *env, uint32_t exception)
42 {
43 helper_raise_exception_err(env, exception, 0);
44 }
45
46 #if !defined(CONFIG_USER_ONLY)
47 void helper_store_msr(CPUPPCState *env, target_ulong val)
48 {
49 val = hreg_store_msr(env, val, 0);
50 if (val != 0) {
51 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
52 helper_raise_exception(env, val);
53 }
54 }
55
56 static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr,
57 target_ulong msrm, int keep_msrh)
58 {
59 #if defined(TARGET_PPC64)
60 if (msr & (1ULL << MSR_SF)) {
61 nip = (uint64_t)nip;
62 msr &= (uint64_t)msrm;
63 } else {
64 nip = (uint32_t)nip;
65 msr = (uint32_t)(msr & msrm);
66 if (keep_msrh) {
67 msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
68 }
69 }
70 #else
71 nip = (uint32_t)nip;
72 msr &= (uint32_t)msrm;
73 #endif
74 /* XXX: beware: this is false if VLE is supported */
75 env->nip = nip & ~((target_ulong)0x00000003);
76 hreg_store_msr(env, msr, 1);
77 #if defined(DEBUG_OP)
78 cpu_dump_rfi(env->nip, env->msr);
79 #endif
80 /* No need to raise an exception here,
81 * as rfi is always the last insn of a TB
82 */
83 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
84 }
85
86 void helper_rfi(CPUPPCState *env)
87 {
88 do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
89 ~((target_ulong)0x783F0000), 1);
90 }
91
92 #if defined(TARGET_PPC64)
93 void helper_rfid(CPUPPCState *env)
94 {
95 do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
96 ~((target_ulong)0x783F0000), 0);
97 }
98
99 void helper_hrfid(CPUPPCState *env)
100 {
101 do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
102 ~((target_ulong)0x783F0000), 0);
103 }
104 #endif
105
106 /*****************************************************************************/
107 /* Embedded PowerPC specific helpers */
108 void helper_40x_rfci(CPUPPCState *env)
109 {
110 do_rfi(env, env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
111 ~((target_ulong)0xFFFF0000), 0);
112 }
113
114 void helper_rfci(CPUPPCState *env)
115 {
116 do_rfi(env, env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
117 ~((target_ulong)0x3FFF0000), 0);
118 }
119
120 void helper_rfdi(CPUPPCState *env)
121 {
122 do_rfi(env, env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
123 ~((target_ulong)0x3FFF0000), 0);
124 }
125
126 void helper_rfmci(CPUPPCState *env)
127 {
128 do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
129 ~((target_ulong)0x3FFF0000), 0);
130 }
131 #endif
132
133 void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
134 uint32_t flags)
135 {
136 if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
137 ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
138 ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
139 ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
140 ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
141 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
142 POWERPC_EXCP_TRAP);
143 }
144 }
145
146 #if defined(TARGET_PPC64)
147 void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
148 uint32_t flags)
149 {
150 if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
151 ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
152 ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
153 ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
154 ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) {
155 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
156 POWERPC_EXCP_TRAP);
157 }
158 }
159 #endif
160
161 #if !defined(CONFIG_USER_ONLY)
162 /*****************************************************************************/
163 /* PowerPC 601 specific instructions (POWER bridge) */
164
165 void helper_rfsvc(CPUPPCState *env)
166 {
167 do_rfi(env, env->lr, env->ctr, 0x0000FFFF, 0);
168 }
169
170 /* Embedded.Processor Control */
171 static int dbell2irq(target_ulong rb)
172 {
173 int msg = rb & DBELL_TYPE_MASK;
174 int irq = -1;
175
176 switch (msg) {
177 case DBELL_TYPE_DBELL:
178 irq = PPC_INTERRUPT_DOORBELL;
179 break;
180 case DBELL_TYPE_DBELL_CRIT:
181 irq = PPC_INTERRUPT_CDOORBELL;
182 break;
183 case DBELL_TYPE_G_DBELL:
184 case DBELL_TYPE_G_DBELL_CRIT:
185 case DBELL_TYPE_G_DBELL_MC:
186 /* XXX implement */
187 default:
188 break;
189 }
190
191 return irq;
192 }
193
194 void helper_msgclr(CPUPPCState *env, target_ulong rb)
195 {
196 int irq = dbell2irq(rb);
197
198 if (irq < 0) {
199 return;
200 }
201
202 env->pending_interrupts &= ~(1 << irq);
203 }
204
205 void helper_msgsnd(target_ulong rb)
206 {
207 int irq = dbell2irq(rb);
208 int pir = rb & DBELL_PIRTAG_MASK;
209 CPUPPCState *cenv;
210
211 if (irq < 0) {
212 return;
213 }
214
215 for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) {
216 if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
217 cenv->pending_interrupts |= 1 << irq;
218 cpu_interrupt(cenv, CPU_INTERRUPT_HARD);
219 }
220 }
221 }
222 #endif