xref: /openbmc/qemu/linux-user/xtensa/cpu_loop.c (revision 2113aed6)
1 /*
2  *  qemu user cpu loop
3  *
4  *  Copyright (c) 2003-2008 Fabrice Bellard
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program 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
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "qemu/osdep.h"
21 #include "qemu.h"
22 #include "cpu_loop-common.h"
23 #include "signal-common.h"
24 
25 static void xtensa_rfw(CPUXtensaState *env)
26 {
27     xtensa_restore_owb(env);
28     env->pc = env->sregs[EPC1];
29 }
30 
31 static void xtensa_rfwu(CPUXtensaState *env)
32 {
33     env->sregs[WINDOW_START] |= (1 << env->sregs[WINDOW_BASE]);
34     xtensa_rfw(env);
35 }
36 
37 static void xtensa_rfwo(CPUXtensaState *env)
38 {
39     env->sregs[WINDOW_START] &= ~(1 << env->sregs[WINDOW_BASE]);
40     xtensa_rfw(env);
41 }
42 
43 static void xtensa_overflow4(CPUXtensaState *env)
44 {
45     put_user_ual(env->regs[0], env->regs[5] - 16);
46     put_user_ual(env->regs[1], env->regs[5] - 12);
47     put_user_ual(env->regs[2], env->regs[5] -  8);
48     put_user_ual(env->regs[3], env->regs[5] -  4);
49     xtensa_rfwo(env);
50 }
51 
52 static void xtensa_underflow4(CPUXtensaState *env)
53 {
54     get_user_ual(env->regs[0], env->regs[5] - 16);
55     get_user_ual(env->regs[1], env->regs[5] - 12);
56     get_user_ual(env->regs[2], env->regs[5] -  8);
57     get_user_ual(env->regs[3], env->regs[5] -  4);
58     xtensa_rfwu(env);
59 }
60 
61 static void xtensa_overflow8(CPUXtensaState *env)
62 {
63     put_user_ual(env->regs[0], env->regs[9] - 16);
64     get_user_ual(env->regs[0], env->regs[1] - 12);
65     put_user_ual(env->regs[1], env->regs[9] - 12);
66     put_user_ual(env->regs[2], env->regs[9] -  8);
67     put_user_ual(env->regs[3], env->regs[9] -  4);
68     put_user_ual(env->regs[4], env->regs[0] - 32);
69     put_user_ual(env->regs[5], env->regs[0] - 28);
70     put_user_ual(env->regs[6], env->regs[0] - 24);
71     put_user_ual(env->regs[7], env->regs[0] - 20);
72     xtensa_rfwo(env);
73 }
74 
75 static void xtensa_underflow8(CPUXtensaState *env)
76 {
77     get_user_ual(env->regs[0], env->regs[9] - 16);
78     get_user_ual(env->regs[1], env->regs[9] - 12);
79     get_user_ual(env->regs[2], env->regs[9] -  8);
80     get_user_ual(env->regs[7], env->regs[1] - 12);
81     get_user_ual(env->regs[3], env->regs[9] -  4);
82     get_user_ual(env->regs[4], env->regs[7] - 32);
83     get_user_ual(env->regs[5], env->regs[7] - 28);
84     get_user_ual(env->regs[6], env->regs[7] - 24);
85     get_user_ual(env->regs[7], env->regs[7] - 20);
86     xtensa_rfwu(env);
87 }
88 
89 static void xtensa_overflow12(CPUXtensaState *env)
90 {
91     put_user_ual(env->regs[0],  env->regs[13] - 16);
92     get_user_ual(env->regs[0],  env->regs[1]  - 12);
93     put_user_ual(env->regs[1],  env->regs[13] - 12);
94     put_user_ual(env->regs[2],  env->regs[13] -  8);
95     put_user_ual(env->regs[3],  env->regs[13] -  4);
96     put_user_ual(env->regs[4],  env->regs[0]  - 48);
97     put_user_ual(env->regs[5],  env->regs[0]  - 44);
98     put_user_ual(env->regs[6],  env->regs[0]  - 40);
99     put_user_ual(env->regs[7],  env->regs[0]  - 36);
100     put_user_ual(env->regs[8],  env->regs[0]  - 32);
101     put_user_ual(env->regs[9],  env->regs[0]  - 28);
102     put_user_ual(env->regs[10], env->regs[0]  - 24);
103     put_user_ual(env->regs[11], env->regs[0]  - 20);
104     xtensa_rfwo(env);
105 }
106 
107 static void xtensa_underflow12(CPUXtensaState *env)
108 {
109     get_user_ual(env->regs[0],  env->regs[13] - 16);
110     get_user_ual(env->regs[1],  env->regs[13] - 12);
111     get_user_ual(env->regs[2],  env->regs[13] -  8);
112     get_user_ual(env->regs[11], env->regs[1]  - 12);
113     get_user_ual(env->regs[3],  env->regs[13] -  4);
114     get_user_ual(env->regs[4],  env->regs[11] - 48);
115     get_user_ual(env->regs[5],  env->regs[11] - 44);
116     get_user_ual(env->regs[6],  env->regs[11] - 40);
117     get_user_ual(env->regs[7],  env->regs[11] - 36);
118     get_user_ual(env->regs[8],  env->regs[11] - 32);
119     get_user_ual(env->regs[9],  env->regs[11] - 28);
120     get_user_ual(env->regs[10], env->regs[11] - 24);
121     get_user_ual(env->regs[11], env->regs[11] - 20);
122     xtensa_rfwu(env);
123 }
124 
125 void cpu_loop(CPUXtensaState *env)
126 {
127     CPUState *cs = env_cpu(env);
128     target_siginfo_t info;
129     abi_ulong ret;
130     int trapnr;
131 
132     while (1) {
133         cpu_exec_start(cs);
134         trapnr = cpu_exec(cs);
135         cpu_exec_end(cs);
136         process_queued_cpu_work(cs);
137 
138         env->sregs[PS] &= ~PS_EXCM;
139         switch (trapnr) {
140         case EXCP_INTERRUPT:
141             break;
142 
143         case EXC_WINDOW_OVERFLOW4:
144             xtensa_overflow4(env);
145             break;
146         case EXC_WINDOW_UNDERFLOW4:
147             xtensa_underflow4(env);
148             break;
149         case EXC_WINDOW_OVERFLOW8:
150             xtensa_overflow8(env);
151             break;
152         case EXC_WINDOW_UNDERFLOW8:
153             xtensa_underflow8(env);
154             break;
155         case EXC_WINDOW_OVERFLOW12:
156             xtensa_overflow12(env);
157             break;
158         case EXC_WINDOW_UNDERFLOW12:
159             xtensa_underflow12(env);
160             break;
161 
162         case EXC_USER:
163             switch (env->sregs[EXCCAUSE]) {
164             case ILLEGAL_INSTRUCTION_CAUSE:
165             case PRIVILEGED_CAUSE:
166                 info.si_signo = TARGET_SIGILL;
167                 info.si_errno = 0;
168                 info.si_code =
169                     env->sregs[EXCCAUSE] == ILLEGAL_INSTRUCTION_CAUSE ?
170                     TARGET_ILL_ILLOPC : TARGET_ILL_PRVOPC;
171                 info._sifields._sigfault._addr = env->sregs[EPC1];
172                 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
173                 break;
174 
175             case SYSCALL_CAUSE:
176                 env->pc += 3;
177                 ret = do_syscall(env, env->regs[2],
178                                  env->regs[6], env->regs[3],
179                                  env->regs[4], env->regs[5],
180                                  env->regs[8], env->regs[9], 0, 0);
181                 switch (ret) {
182                 default:
183                     env->regs[2] = ret;
184                     break;
185 
186                 case -TARGET_ERESTARTSYS:
187                     env->pc -= 3;
188                     break;
189 
190                 case -TARGET_QEMU_ESIGRETURN:
191                     break;
192                 }
193                 break;
194 
195             case ALLOCA_CAUSE:
196                 env->sregs[PS] = deposit32(env->sregs[PS],
197                                            PS_OWB_SHIFT,
198                                            PS_OWB_LEN,
199                                            env->sregs[WINDOW_BASE]);
200 
201                 switch (env->regs[0] & 0xc0000000) {
202                 case 0x00000000:
203                 case 0x40000000:
204                     xtensa_rotate_window(env, -1);
205                     xtensa_underflow4(env);
206                     break;
207 
208                 case 0x80000000:
209                     xtensa_rotate_window(env, -2);
210                     xtensa_underflow8(env);
211                     break;
212 
213                 case 0xc0000000:
214                     xtensa_rotate_window(env, -3);
215                     xtensa_underflow12(env);
216                     break;
217                 }
218                 break;
219 
220             case INTEGER_DIVIDE_BY_ZERO_CAUSE:
221                 info.si_signo = TARGET_SIGFPE;
222                 info.si_errno = 0;
223                 info.si_code = TARGET_FPE_INTDIV;
224                 info._sifields._sigfault._addr = env->sregs[EPC1];
225                 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
226                 break;
227 
228             case LOAD_PROHIBITED_CAUSE:
229             case STORE_PROHIBITED_CAUSE:
230                 info.si_signo = TARGET_SIGSEGV;
231                 info.si_errno = 0;
232                 info.si_code = TARGET_SEGV_ACCERR;
233                 info._sifields._sigfault._addr = env->sregs[EXCVADDR];
234                 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
235                 break;
236 
237             default:
238                 fprintf(stderr, "exccause = %d\n", env->sregs[EXCCAUSE]);
239                 g_assert_not_reached();
240             }
241             break;
242         case EXCP_DEBUG:
243             info.si_signo = TARGET_SIGTRAP;
244             info.si_errno = 0;
245             info.si_code = TARGET_TRAP_BRKPT;
246             queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
247             break;
248         case EXC_DEBUG:
249         default:
250             fprintf(stderr, "trapnr = %d\n", trapnr);
251             g_assert_not_reached();
252         }
253         process_pending_signals(env);
254     }
255 }
256 
257 void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
258 {
259     int i;
260     for (i = 0; i < 16; ++i) {
261         env->regs[i] = regs->areg[i];
262     }
263     env->sregs[WINDOW_START] = regs->windowstart;
264     env->pc = regs->pc;
265 }
266