]> git.proxmox.com Git - qemu.git/blame - target-ppc/excp_helper.c
ppc: Avoid AREG0 for exception helpers
[qemu.git] / target-ppc / excp_helper.c
CommitLineData
ad71ed68
BS
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"
ad71ed68
BS
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
e5f17ac6
BS
30void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
31 uint32_t error_code)
ad71ed68
BS
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
e5f17ac6 41void helper_raise_exception(CPUPPCState *env, uint32_t exception)
ad71ed68 42{
e5f17ac6 43 helper_raise_exception_err(env, exception, 0);
ad71ed68
BS
44}
45
46#if !defined(CONFIG_USER_ONLY)
e5f17ac6 47void helper_store_msr(CPUPPCState *env, target_ulong val)
ad71ed68
BS
48{
49 val = hreg_store_msr(env, val, 0);
50 if (val != 0) {
51 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
e5f17ac6 52 helper_raise_exception(env, val);
ad71ed68
BS
53 }
54}
55
e5f17ac6 56static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr,
ad71ed68
BS
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
e5f17ac6 86void helper_rfi(CPUPPCState *env)
ad71ed68 87{
e5f17ac6 88 do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
ad71ed68
BS
89 ~((target_ulong)0x783F0000), 1);
90}
91
92#if defined(TARGET_PPC64)
e5f17ac6 93void helper_rfid(CPUPPCState *env)
ad71ed68 94{
e5f17ac6 95 do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
ad71ed68
BS
96 ~((target_ulong)0x783F0000), 0);
97}
98
e5f17ac6 99void helper_hrfid(CPUPPCState *env)
ad71ed68 100{
e5f17ac6 101 do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
ad71ed68
BS
102 ~((target_ulong)0x783F0000), 0);
103}
104#endif
105
106/*****************************************************************************/
107/* Embedded PowerPC specific helpers */
e5f17ac6 108void helper_40x_rfci(CPUPPCState *env)
ad71ed68 109{
e5f17ac6 110 do_rfi(env, env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
ad71ed68
BS
111 ~((target_ulong)0xFFFF0000), 0);
112}
113
e5f17ac6 114void helper_rfci(CPUPPCState *env)
ad71ed68 115{
e5f17ac6 116 do_rfi(env, env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
ad71ed68
BS
117 ~((target_ulong)0x3FFF0000), 0);
118}
119
e5f17ac6 120void helper_rfdi(CPUPPCState *env)
ad71ed68 121{
e5f17ac6 122 do_rfi(env, env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
ad71ed68
BS
123 ~((target_ulong)0x3FFF0000), 0);
124}
125
e5f17ac6 126void helper_rfmci(CPUPPCState *env)
ad71ed68 127{
e5f17ac6 128 do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
ad71ed68
BS
129 ~((target_ulong)0x3FFF0000), 0);
130}
131#endif
132
e5f17ac6
BS
133void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
134 uint32_t flags)
ad71ed68
BS
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))))) {
e5f17ac6
BS
141 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
142 POWERPC_EXCP_TRAP);
ad71ed68
BS
143 }
144}
145
146#if defined(TARGET_PPC64)
e5f17ac6
BS
147void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
148 uint32_t flags)
ad71ed68
BS
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))))) {
e5f17ac6
BS
155 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
156 POWERPC_EXCP_TRAP);
ad71ed68
BS
157 }
158}
159#endif
160
161#if !defined(CONFIG_USER_ONLY)
162/*****************************************************************************/
163/* PowerPC 601 specific instructions (POWER bridge) */
164
e5f17ac6 165void helper_rfsvc(CPUPPCState *env)
ad71ed68 166{
e5f17ac6 167 do_rfi(env, env->lr, env->ctr, 0x0000FFFF, 0);
ad71ed68
BS
168}
169
170/* Embedded.Processor Control */
171static 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
e5f17ac6 194void helper_msgclr(CPUPPCState *env, target_ulong rb)
ad71ed68
BS
195{
196 int irq = dbell2irq(rb);
197
198 if (irq < 0) {
199 return;
200 }
201
202 env->pending_interrupts &= ~(1 << irq);
203}
204
205void 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