Fix elf loader range checking
[qemu] / target-alpha / helper.c
1 /*
2  *  Alpha emulation cpu helpers for qemu.
3  *
4  *  Copyright (c) 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, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
19  */
20
21 #include <stdint.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24
25 #include "cpu.h"
26 #include "exec-all.h"
27
28 #if defined(CONFIG_USER_ONLY)
29
30 int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
31                                 int mmu_idx, int is_softmmu)
32 {
33     if (rw == 2)
34         env->exception_index = EXCP_ITB_MISS;
35     else
36         env->exception_index = EXCP_DFAULT;
37     env->ipr[IPR_EXC_ADDR] = address;
38
39     return 1;
40 }
41
42 target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
43 {
44     return addr;
45 }
46
47 void do_interrupt (CPUState *env)
48 {
49     env->exception_index = -1;
50 }
51
52 #else
53
54 target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
55 {
56     return -1;
57 }
58
59 int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
60                                 int mmu_idx, int is_softmmu)
61 {
62     uint32_t opc;
63
64     if (rw == 2) {
65         /* Instruction translation buffer miss */
66         env->exception_index = EXCP_ITB_MISS;
67     } else {
68         if (env->ipr[IPR_EXC_ADDR] & 1)
69             env->exception_index = EXCP_DTB_MISS_PAL;
70         else
71             env->exception_index = EXCP_DTB_MISS_NATIVE;
72         opc = (ldl_code(env->pc) >> 21) << 4;
73         if (rw) {
74             opc |= 0x9;
75         } else {
76             opc |= 0x4;
77         }
78         env->ipr[IPR_MM_STAT] = opc;
79     }
80
81     return 1;
82 }
83
84 int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp)
85 {
86     uint64_t hwpcb;
87     int ret = 0;
88
89     hwpcb = env->ipr[IPR_PCBB];
90     switch (iprn) {
91     case IPR_ASN:
92         if (env->features & FEATURE_ASN)
93             *valp = env->ipr[IPR_ASN];
94         else
95             *valp = 0;
96         break;
97     case IPR_ASTEN:
98         *valp = ((int64_t)(env->ipr[IPR_ASTEN] << 60)) >> 60;
99         break;
100     case IPR_ASTSR:
101         *valp = ((int64_t)(env->ipr[IPR_ASTSR] << 60)) >> 60;
102         break;
103     case IPR_DATFX:
104         /* Write only */
105         ret = -1;
106         break;
107     case IPR_ESP:
108         if (env->features & FEATURE_SPS)
109             *valp = env->ipr[IPR_ESP];
110         else
111             *valp = ldq_raw(hwpcb + 8);
112         break;
113     case IPR_FEN:
114         *valp = ((int64_t)(env->ipr[IPR_FEN] << 63)) >> 63;
115         break;
116     case IPR_IPIR:
117         /* Write-only */
118         ret = -1;
119         break;
120     case IPR_IPL:
121         *valp = ((int64_t)(env->ipr[IPR_IPL] << 59)) >> 59;
122         break;
123     case IPR_KSP:
124         if (!(env->ipr[IPR_EXC_ADDR] & 1)) {
125             ret = -1;
126         } else {
127             if (env->features & FEATURE_SPS)
128                 *valp = env->ipr[IPR_KSP];
129             else
130                 *valp = ldq_raw(hwpcb + 0);
131         }
132         break;
133     case IPR_MCES:
134         *valp = ((int64_t)(env->ipr[IPR_MCES] << 59)) >> 59;
135         break;
136     case IPR_PERFMON:
137         /* Implementation specific */
138         *valp = 0;
139         break;
140     case IPR_PCBB:
141         *valp = ((int64_t)env->ipr[IPR_PCBB] << 16) >> 16;
142         break;
143     case IPR_PRBR:
144         *valp = env->ipr[IPR_PRBR];
145         break;
146     case IPR_PTBR:
147         *valp = env->ipr[IPR_PTBR];
148         break;
149     case IPR_SCBB:
150         *valp = (int64_t)((int32_t)env->ipr[IPR_SCBB]);
151         break;
152     case IPR_SIRR:
153         /* Write-only */
154         ret = -1;
155         break;
156     case IPR_SISR:
157         *valp = (int64_t)((int16_t)env->ipr[IPR_SISR]);
158     case IPR_SSP:
159         if (env->features & FEATURE_SPS)
160             *valp = env->ipr[IPR_SSP];
161         else
162             *valp = ldq_raw(hwpcb + 16);
163         break;
164     case IPR_SYSPTBR:
165         if (env->features & FEATURE_VIRBND)
166             *valp = env->ipr[IPR_SYSPTBR];
167         else
168             ret = -1;
169         break;
170     case IPR_TBCHK:
171         if ((env->features & FEATURE_TBCHK)) {
172             /* XXX: TODO */
173             *valp = 0;
174             ret = -1;
175         } else {
176             ret = -1;
177         }
178         break;
179     case IPR_TBIA:
180         /* Write-only */
181         ret = -1;
182         break;
183     case IPR_TBIAP:
184         /* Write-only */
185         ret = -1;
186         break;
187     case IPR_TBIS:
188         /* Write-only */
189         ret = -1;
190         break;
191     case IPR_TBISD:
192         /* Write-only */
193         ret = -1;
194         break;
195     case IPR_TBISI:
196         /* Write-only */
197         ret = -1;
198         break;
199     case IPR_USP:
200         if (env->features & FEATURE_SPS)
201             *valp = env->ipr[IPR_USP];
202         else
203             *valp = ldq_raw(hwpcb + 24);
204         break;
205     case IPR_VIRBND:
206         if (env->features & FEATURE_VIRBND)
207             *valp = env->ipr[IPR_VIRBND];
208         else
209             ret = -1;
210         break;
211     case IPR_VPTB:
212         *valp = env->ipr[IPR_VPTB];
213         break;
214     case IPR_WHAMI:
215         *valp = env->ipr[IPR_WHAMI];
216         break;
217     default:
218         /* Invalid */
219         ret = -1;
220         break;
221     }
222
223     return ret;
224 }
225
226 int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp)
227 {
228     uint64_t hwpcb, tmp64;
229     uint8_t tmp8;
230     int ret = 0;
231
232     hwpcb = env->ipr[IPR_PCBB];
233     switch (iprn) {
234     case IPR_ASN:
235         /* Read-only */
236         ret = -1;
237         break;
238     case IPR_ASTEN:
239         tmp8 = ((int8_t)(env->ipr[IPR_ASTEN] << 4)) >> 4;
240         *oldvalp = tmp8;
241         tmp8 &= val & 0xF;
242         tmp8 |= (val >> 4) & 0xF;
243         env->ipr[IPR_ASTEN] &= ~0xF;
244         env->ipr[IPR_ASTEN] |= tmp8;
245         ret = 1;
246         break;
247     case IPR_ASTSR:
248         tmp8 = ((int8_t)(env->ipr[IPR_ASTSR] << 4)) >> 4;
249         *oldvalp = tmp8;
250         tmp8 &= val & 0xF;
251         tmp8 |= (val >> 4) & 0xF;
252         env->ipr[IPR_ASTSR] &= ~0xF;
253         env->ipr[IPR_ASTSR] |= tmp8;
254         ret = 1;
255     case IPR_DATFX:
256         env->ipr[IPR_DATFX] &= ~0x1;
257         env->ipr[IPR_DATFX] |= val & 1;
258         tmp64 = ldq_raw(hwpcb + 56);
259         tmp64 &= ~0x8000000000000000ULL;
260         tmp64 |= (val & 1) << 63;
261         stq_raw(hwpcb + 56, tmp64);
262         break;
263     case IPR_ESP:
264         if (env->features & FEATURE_SPS)
265             env->ipr[IPR_ESP] = val;
266         else
267             stq_raw(hwpcb + 8, val);
268         break;
269     case IPR_FEN:
270         env->ipr[IPR_FEN] = val & 1;
271         tmp64 = ldq_raw(hwpcb + 56);
272         tmp64 &= ~1;
273         tmp64 |= val & 1;
274         stq_raw(hwpcb + 56, tmp64);
275         break;
276     case IPR_IPIR:
277         /* XXX: TODO: Send IRQ to CPU #ir[16] */
278         break;
279     case IPR_IPL:
280         *oldvalp = ((int64_t)(env->ipr[IPR_IPL] << 59)) >> 59;
281         env->ipr[IPR_IPL] &= ~0x1F;
282         env->ipr[IPR_IPL] |= val & 0x1F;
283         /* XXX: may issue an interrupt or ASR _now_ */
284         ret = 1;
285         break;
286     case IPR_KSP:
287         if (!(env->ipr[IPR_EXC_ADDR] & 1)) {
288             ret = -1;
289         } else {
290             if (env->features & FEATURE_SPS)
291                 env->ipr[IPR_KSP] = val;
292             else
293                 stq_raw(hwpcb + 0, val);
294         }
295         break;
296     case IPR_MCES:
297         env->ipr[IPR_MCES] &= ~((val & 0x7) | 0x18);
298         env->ipr[IPR_MCES] |= val & 0x18;
299         break;
300     case IPR_PERFMON:
301         /* Implementation specific */
302         *oldvalp = 0;
303         ret = 1;
304         break;
305     case IPR_PCBB:
306         /* Read-only */
307         ret = -1;
308         break;
309     case IPR_PRBR:
310         env->ipr[IPR_PRBR] = val;
311         break;
312     case IPR_PTBR:
313         /* Read-only */
314         ret = -1;
315         break;
316     case IPR_SCBB:
317         env->ipr[IPR_SCBB] = (uint32_t)val;
318         break;
319     case IPR_SIRR:
320         if (val & 0xF) {
321             env->ipr[IPR_SISR] |= 1 << (val & 0xF);
322             /* XXX: request a software interrupt _now_ */
323         }
324         break;
325     case IPR_SISR:
326         /* Read-only */
327         ret = -1;
328         break;
329     case IPR_SSP:
330         if (env->features & FEATURE_SPS)
331             env->ipr[IPR_SSP] = val;
332         else
333             stq_raw(hwpcb + 16, val);
334         break;
335     case IPR_SYSPTBR:
336         if (env->features & FEATURE_VIRBND)
337             env->ipr[IPR_SYSPTBR] = val;
338         else
339             ret = -1;
340     case IPR_TBCHK:
341         /* Read-only */
342         ret = -1;
343         break;
344     case IPR_TBIA:
345         tlb_flush(env, 1);
346         break;
347     case IPR_TBIAP:
348         tlb_flush(env, 1);
349         break;
350     case IPR_TBIS:
351         tlb_flush_page(env, val);
352         break;
353     case IPR_TBISD:
354         tlb_flush_page(env, val);
355         break;
356     case IPR_TBISI:
357         tlb_flush_page(env, val);
358         break;
359     case IPR_USP:
360         if (env->features & FEATURE_SPS)
361             env->ipr[IPR_USP] = val;
362         else
363             stq_raw(hwpcb + 24, val);
364         break;
365     case IPR_VIRBND:
366         if (env->features & FEATURE_VIRBND)
367             env->ipr[IPR_VIRBND] = val;
368         else
369             ret = -1;
370         break;
371     case IPR_VPTB:
372         env->ipr[IPR_VPTB] = val;
373         break;
374     case IPR_WHAMI:
375         /* Read-only */
376         ret = -1;
377         break;
378     default:
379         /* Invalid */
380         ret = -1;
381         break;
382     }
383
384     return ret;
385 }
386
387 void do_interrupt (CPUState *env)
388 {
389     int excp;
390
391     env->ipr[IPR_EXC_ADDR] = env->pc | 1;
392     excp = env->exception_index;
393     env->exception_index = 0;
394     env->error_code = 0;
395     /* XXX: disable interrupts and memory mapping */
396     if (env->ipr[IPR_PAL_BASE] != -1ULL) {
397         /* We use native PALcode */
398         env->pc = env->ipr[IPR_PAL_BASE] + excp;
399     } else {
400         /* We use emulated PALcode */
401         call_pal(env);
402         /* Emulate REI */
403         env->pc = env->ipr[IPR_EXC_ADDR] & ~7;
404         env->ipr[IPR_EXC_ADDR] = env->ipr[IPR_EXC_ADDR] & 1;
405         /* XXX: re-enable interrupts and memory mapping */
406     }
407 }
408 #endif
409
410 void cpu_dump_state (CPUState *env, FILE *f,
411                      int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
412                      int flags)
413 {
414     static const char *linux_reg_names[] = {
415         "v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ",
416         "t7 ", "s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "fp ",
417         "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ",
418         "t10", "t11", "ra ", "t12", "at ", "gp ", "sp ", "zero",
419     };
420     int i;
421
422     cpu_fprintf(f, "     PC  " TARGET_FMT_lx "      PS  " TARGET_FMT_lx "\n",
423                 env->pc, env->ps);
424     for (i = 0; i < 31; i++) {
425         cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx " ", i,
426                     linux_reg_names[i], env->ir[i]);
427         if ((i % 3) == 2)
428             cpu_fprintf(f, "\n");
429     }
430     cpu_fprintf(f, "\n");
431     for (i = 0; i < 31; i++) {
432         cpu_fprintf(f, "FIR%02d    " TARGET_FMT_lx " ", i,
433                     *((uint64_t *)(&env->fir[i])));
434         if ((i % 3) == 2)
435             cpu_fprintf(f, "\n");
436     }
437     cpu_fprintf(f, "\nlock     " TARGET_FMT_lx "\n", env->lock);
438 }