]> git.proxmox.com Git - mirror_qemu.git/blame - target-arm/helper.c
Fix typo in help output.
[mirror_qemu.git] / target-arm / helper.c
CommitLineData
b5ff1b31
FB
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4
5#include "cpu.h"
6#include "exec-all.h"
7
40f137e1
PB
8void cpu_reset(CPUARMState *env)
9{
10#if defined (CONFIG_USER_ONLY)
11 env->uncached_cpsr = ARM_CPU_MODE_USR;
12 env->vfp.xregs[ARM_VFP_FPEXC] = 1 << 30;
13#else
14 /* SVC mode with interrupts disabled. */
15 env->uncached_cpsr = ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I;
16 env->vfp.xregs[ARM_VFP_FPEXC] = 0;
17#endif
18 env->regs[15] = 0;
19}
20
21CPUARMState *cpu_arm_init(void)
22{
23 CPUARMState *env;
24
25 env = qemu_mallocz(sizeof(CPUARMState));
26 if (!env)
27 return NULL;
28 cpu_exec_init(env);
29 cpu_reset(env);
30 tlb_flush(env, 1);
31 return env;
32}
33
34static inline void set_feature(CPUARMState *env, int feature)
35{
36 env->features |= 1u << feature;
37}
38
3371d272
PB
39struct arm_cpu_t {
40 uint32_t id;
41 const char *name;
42};
43
44static const struct arm_cpu_t arm_cpu_names[] = {
45 { ARM_CPUID_ARM926, "arm926"},
46 { ARM_CPUID_ARM1026, "arm1026"},
47 { 0, NULL}
48};
49
5adb4839
PB
50void arm_cpu_list(void)
51{
52 int i;
53
54 printf ("Available CPUs:\n");
55 for (i = 0; arm_cpu_names[i].name; i++) {
56 printf(" %s\n", arm_cpu_names[i].name);
57 }
58}
59
3371d272 60void cpu_arm_set_model(CPUARMState *env, const char *name)
40f137e1 61{
3371d272
PB
62 int i;
63 uint32_t id;
64
65 id = 0;
66 i = 0;
67 for (i = 0; arm_cpu_names[i].name; i++) {
68 if (strcmp(name, arm_cpu_names[i].name) == 0) {
69 id = arm_cpu_names[i].id;
70 break;
71 }
72 }
73 if (!id) {
74 cpu_abort(env, "Unknown CPU '%s'", name);
75 return;
76 }
77
40f137e1
PB
78 env->cp15.c0_cpuid = id;
79 switch (id) {
80 case ARM_CPUID_ARM926:
81 set_feature(env, ARM_FEATURE_VFP);
82 env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090;
83 break;
84 case ARM_CPUID_ARM1026:
85 set_feature(env, ARM_FEATURE_VFP);
86 set_feature(env, ARM_FEATURE_AUXCR);
87 env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0;
88 break;
89 default:
90 cpu_abort(env, "Bad CPU ID: %x\n", id);
91 break;
92 }
93}
94
95void cpu_arm_close(CPUARMState *env)
96{
97 free(env);
98}
99
b5ff1b31
FB
100#if defined(CONFIG_USER_ONLY)
101
102void do_interrupt (CPUState *env)
103{
104 env->exception_index = -1;
105}
106
107int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
108 int is_user, int is_softmmu)
109{
110 if (rw == 2) {
111 env->exception_index = EXCP_PREFETCH_ABORT;
112 env->cp15.c6_insn = address;
113 } else {
114 env->exception_index = EXCP_DATA_ABORT;
115 env->cp15.c6_data = address;
116 }
117 return 1;
118}
119
120target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
121{
122 return addr;
123}
124
125/* These should probably raise undefined insn exceptions. */
126void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val)
127{
128 cpu_abort(env, "cp15 insn %08x\n", insn);
129}
130
131uint32_t helper_get_cp15(CPUState *env, uint32_t insn)
132{
133 cpu_abort(env, "cp15 insn %08x\n", insn);
134 return 0;
135}
136
137void switch_mode(CPUState *env, int mode)
138{
139 if (mode != ARM_CPU_MODE_USR)
140 cpu_abort(env, "Tried to switch out of user mode\n");
141}
142
143#else
144
8e71621f
PB
145extern int semihosting_enabled;
146
b5ff1b31
FB
147/* Map CPU modes onto saved register banks. */
148static inline int bank_number (int mode)
149{
150 switch (mode) {
151 case ARM_CPU_MODE_USR:
152 case ARM_CPU_MODE_SYS:
153 return 0;
154 case ARM_CPU_MODE_SVC:
155 return 1;
156 case ARM_CPU_MODE_ABT:
157 return 2;
158 case ARM_CPU_MODE_UND:
159 return 3;
160 case ARM_CPU_MODE_IRQ:
161 return 4;
162 case ARM_CPU_MODE_FIQ:
163 return 5;
164 }
165 cpu_abort(cpu_single_env, "Bad mode %x\n", mode);
166 return -1;
167}
168
169void switch_mode(CPUState *env, int mode)
170{
171 int old_mode;
172 int i;
173
174 old_mode = env->uncached_cpsr & CPSR_M;
175 if (mode == old_mode)
176 return;
177
178 if (old_mode == ARM_CPU_MODE_FIQ) {
179 memcpy (env->fiq_regs, env->regs + 8, 5 * sizeof(uint32_t));
8637c67f 180 memcpy (env->regs + 8, env->usr_regs, 5 * sizeof(uint32_t));
b5ff1b31
FB
181 } else if (mode == ARM_CPU_MODE_FIQ) {
182 memcpy (env->usr_regs, env->regs + 8, 5 * sizeof(uint32_t));
8637c67f 183 memcpy (env->regs + 8, env->fiq_regs, 5 * sizeof(uint32_t));
b5ff1b31
FB
184 }
185
186 i = bank_number(old_mode);
187 env->banked_r13[i] = env->regs[13];
188 env->banked_r14[i] = env->regs[14];
189 env->banked_spsr[i] = env->spsr;
190
191 i = bank_number(mode);
192 env->regs[13] = env->banked_r13[i];
193 env->regs[14] = env->banked_r14[i];
194 env->spsr = env->banked_spsr[i];
195}
196
197/* Handle a CPU exception. */
198void do_interrupt(CPUARMState *env)
199{
200 uint32_t addr;
201 uint32_t mask;
202 int new_mode;
203 uint32_t offset;
204
205 /* TODO: Vectored interrupt controller. */
206 switch (env->exception_index) {
207 case EXCP_UDEF:
208 new_mode = ARM_CPU_MODE_UND;
209 addr = 0x04;
210 mask = CPSR_I;
211 if (env->thumb)
212 offset = 2;
213 else
214 offset = 4;
215 break;
216 case EXCP_SWI:
8e71621f
PB
217 if (semihosting_enabled) {
218 /* Check for semihosting interrupt. */
219 if (env->thumb) {
220 mask = lduw_code(env->regs[15] - 2) & 0xff;
221 } else {
222 mask = ldl_code(env->regs[15] - 4) & 0xffffff;
223 }
224 /* Only intercept calls from privileged modes, to provide some
225 semblance of security. */
226 if (((mask == 0x123456 && !env->thumb)
227 || (mask == 0xab && env->thumb))
228 && (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR) {
229 env->regs[0] = do_arm_semihosting(env);
230 return;
231 }
232 }
b5ff1b31
FB
233 new_mode = ARM_CPU_MODE_SVC;
234 addr = 0x08;
235 mask = CPSR_I;
236 /* The PC already points to the next instructon. */
237 offset = 0;
238 break;
239 case EXCP_PREFETCH_ABORT:
06c949e6 240 case EXCP_BKPT:
b5ff1b31
FB
241 new_mode = ARM_CPU_MODE_ABT;
242 addr = 0x0c;
243 mask = CPSR_A | CPSR_I;
244 offset = 4;
245 break;
246 case EXCP_DATA_ABORT:
247 new_mode = ARM_CPU_MODE_ABT;
248 addr = 0x10;
249 mask = CPSR_A | CPSR_I;
250 offset = 8;
251 break;
252 case EXCP_IRQ:
253 new_mode = ARM_CPU_MODE_IRQ;
254 addr = 0x18;
255 /* Disable IRQ and imprecise data aborts. */
256 mask = CPSR_A | CPSR_I;
257 offset = 4;
258 break;
259 case EXCP_FIQ:
260 new_mode = ARM_CPU_MODE_FIQ;
261 addr = 0x1c;
262 /* Disable FIQ, IRQ and imprecise data aborts. */
263 mask = CPSR_A | CPSR_I | CPSR_F;
264 offset = 4;
265 break;
266 default:
267 cpu_abort(env, "Unhandled exception 0x%x\n", env->exception_index);
268 return; /* Never happens. Keep compiler happy. */
269 }
270 /* High vectors. */
271 if (env->cp15.c1_sys & (1 << 13)) {
272 addr += 0xffff0000;
273 }
274 switch_mode (env, new_mode);
275 env->spsr = cpsr_read(env);
6d7e6326 276 /* Switch to the new mode, and switch to Arm mode. */
b5ff1b31 277 /* ??? Thumb interrupt handlers not implemented. */
6d7e6326 278 env->uncached_cpsr = (env->uncached_cpsr & ~CPSR_M) | new_mode;
b5ff1b31 279 env->uncached_cpsr |= mask;
6d7e6326 280 env->thumb = 0;
b5ff1b31
FB
281 env->regs[14] = env->regs[15] + offset;
282 env->regs[15] = addr;
283 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
284}
285
286/* Check section/page access permissions.
287 Returns the page protection flags, or zero if the access is not
288 permitted. */
289static inline int check_ap(CPUState *env, int ap, int domain, int access_type,
290 int is_user)
291{
292 if (domain == 3)
293 return PAGE_READ | PAGE_WRITE;
294
295 switch (ap) {
296 case 0:
78600320 297 if (access_type == 1)
b5ff1b31
FB
298 return 0;
299 switch ((env->cp15.c1_sys >> 8) & 3) {
300 case 1:
301 return is_user ? 0 : PAGE_READ;
302 case 2:
303 return PAGE_READ;
304 default:
305 return 0;
306 }
307 case 1:
308 return is_user ? 0 : PAGE_READ | PAGE_WRITE;
309 case 2:
310 if (is_user)
311 return (access_type == 1) ? 0 : PAGE_READ;
312 else
313 return PAGE_READ | PAGE_WRITE;
314 case 3:
315 return PAGE_READ | PAGE_WRITE;
316 default:
317 abort();
318 }
319}
320
321static int get_phys_addr(CPUState *env, uint32_t address, int access_type,
322 int is_user, uint32_t *phys_ptr, int *prot)
323{
324 int code;
325 uint32_t table;
326 uint32_t desc;
327 int type;
328 int ap;
329 int domain;
330 uint32_t phys_addr;
331
332 /* Fast Context Switch Extension. */
333 if (address < 0x02000000)
334 address += env->cp15.c13_fcse;
335
336 if ((env->cp15.c1_sys & 1) == 0) {
337 /* MMU diusabled. */
338 *phys_ptr = address;
339 *prot = PAGE_READ | PAGE_WRITE;
340 } else {
341 /* Pagetable walk. */
342 /* Lookup l1 descriptor. */
343 table = (env->cp15.c2 & 0xffffc000) | ((address >> 18) & 0x3ffc);
344 desc = ldl_phys(table);
345 type = (desc & 3);
346 domain = (env->cp15.c3 >> ((desc >> 4) & 0x1e)) & 3;
347 if (type == 0) {
348 /* Secton translation fault. */
349 code = 5;
350 goto do_fault;
351 }
352 if (domain == 0 || domain == 2) {
353 if (type == 2)
354 code = 9; /* Section domain fault. */
355 else
356 code = 11; /* Page domain fault. */
357 goto do_fault;
358 }
359 if (type == 2) {
360 /* 1Mb section. */
361 phys_addr = (desc & 0xfff00000) | (address & 0x000fffff);
362 ap = (desc >> 10) & 3;
363 code = 13;
364 } else {
365 /* Lookup l2 entry. */
366 table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc);
367 desc = ldl_phys(table);
368 switch (desc & 3) {
369 case 0: /* Page translation fault. */
370 code = 7;
371 goto do_fault;
372 case 1: /* 64k page. */
373 phys_addr = (desc & 0xffff0000) | (address & 0xffff);
374 ap = (desc >> (4 + ((address >> 13) & 6))) & 3;
375 break;
376 case 2: /* 4k page. */
377 phys_addr = (desc & 0xfffff000) | (address & 0xfff);
378 ap = (desc >> (4 + ((address >> 13) & 6))) & 3;
379 break;
380 case 3: /* 1k page. */
381 if (type == 1) {
382 /* Page translation fault. */
383 code = 7;
384 goto do_fault;
385 }
386 phys_addr = (desc & 0xfffffc00) | (address & 0x3ff);
387 ap = (desc >> 4) & 3;
388 break;
389 default:
390 /* Never happens, but compiler isn't smart enough to tell. */
391 abort();
392 }
393 code = 15;
394 }
395 *prot = check_ap(env, ap, domain, access_type, is_user);
396 if (!*prot) {
397 /* Access permission fault. */
398 goto do_fault;
399 }
400 *phys_ptr = phys_addr;
401 }
402 return 0;
403do_fault:
404 return code | (domain << 4);
405}
406
407int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address,
408 int access_type, int is_user, int is_softmmu)
409{
410 uint32_t phys_addr;
411 int prot;
412 int ret;
413
414 ret = get_phys_addr(env, address, access_type, is_user, &phys_addr, &prot);
415 if (ret == 0) {
416 /* Map a single [sub]page. */
417 phys_addr &= ~(uint32_t)0x3ff;
418 address &= ~(uint32_t)0x3ff;
419 return tlb_set_page (env, address, phys_addr, prot, is_user,
420 is_softmmu);
421 }
422
423 if (access_type == 2) {
424 env->cp15.c5_insn = ret;
425 env->cp15.c6_insn = address;
426 env->exception_index = EXCP_PREFETCH_ABORT;
427 } else {
428 env->cp15.c5_data = ret;
429 env->cp15.c6_data = address;
430 env->exception_index = EXCP_DATA_ABORT;
431 }
432 return 1;
433}
434
435target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
436{
437 uint32_t phys_addr;
438 int prot;
439 int ret;
440
441 ret = get_phys_addr(env, addr, 0, 0, &phys_addr, &prot);
442
443 if (ret != 0)
444 return -1;
445
446 return phys_addr;
447}
448
449void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val)
450{
451 uint32_t op2;
452
453 op2 = (insn >> 5) & 7;
454 switch ((insn >> 16) & 0xf) {
455 case 0: /* ID codes. */
456 goto bad_reg;
457 case 1: /* System configuration. */
458 switch (op2) {
459 case 0:
460 env->cp15.c1_sys = val;
461 /* ??? Lots of these bits are not implemented. */
462 /* This may enable/disable the MMU, so do a TLB flush. */
463 tlb_flush(env, 1);
464 break;
465 case 2:
466 env->cp15.c1_coproc = val;
467 /* ??? Is this safe when called from within a TB? */
468 tb_flush(env);
469 default:
470 goto bad_reg;
471 }
472 break;
473 case 2: /* MMU Page table control. */
474 env->cp15.c2 = val;
475 break;
476 case 3: /* MMU Domain access control. */
477 env->cp15.c3 = val;
478 break;
479 case 4: /* Reserved. */
480 goto bad_reg;
481 case 5: /* MMU Fault status. */
482 switch (op2) {
483 case 0:
484 env->cp15.c5_data = val;
485 break;
486 case 1:
487 env->cp15.c5_insn = val;
488 break;
489 default:
490 goto bad_reg;
491 }
492 break;
493 case 6: /* MMU Fault address. */
494 switch (op2) {
495 case 0:
496 env->cp15.c6_data = val;
497 break;
498 case 1:
499 env->cp15.c6_insn = val;
500 break;
501 default:
502 goto bad_reg;
503 }
504 break;
505 case 7: /* Cache control. */
506 /* No cache, so nothing to do. */
507 break;
508 case 8: /* MMU TLB control. */
509 switch (op2) {
510 case 0: /* Invalidate all. */
511 tlb_flush(env, 0);
512 break;
513 case 1: /* Invalidate single TLB entry. */
514#if 0
515 /* ??? This is wrong for large pages and sections. */
516 /* As an ugly hack to make linux work we always flush a 4K
517 pages. */
518 val &= 0xfffff000;
519 tlb_flush_page(env, val);
520 tlb_flush_page(env, val + 0x400);
521 tlb_flush_page(env, val + 0x800);
522 tlb_flush_page(env, val + 0xc00);
523#else
524 tlb_flush(env, 1);
525#endif
526 break;
527 default:
528 goto bad_reg;
529 }
530 break;
531 case 9: /* Cache lockdown. */
532 switch (op2) {
533 case 0:
534 env->cp15.c9_data = val;
535 break;
536 case 1:
537 env->cp15.c9_insn = val;
538 break;
539 default:
540 goto bad_reg;
541 }
542 break;
543 case 10: /* MMU TLB lockdown. */
544 /* ??? TLB lockdown not implemented. */
545 break;
546 case 11: /* TCM DMA control. */
547 case 12: /* Reserved. */
548 goto bad_reg;
549 case 13: /* Process ID. */
550 switch (op2) {
551 case 0:
d07edbfa
PB
552 /* Unlike real hardware the qemu TLB uses virtual addresses,
553 not modified virtual addresses, so this causes a TLB flush.
554 */
555 if (env->cp15.c13_fcse != val)
556 tlb_flush(env, 1);
557 env->cp15.c13_fcse = val;
b5ff1b31
FB
558 break;
559 case 1:
d07edbfa
PB
560 /* This changes the ASID, so do a TLB flush. */
561 if (env->cp15.c13_context != val)
562 tlb_flush(env, 0);
563 env->cp15.c13_context = val;
b5ff1b31
FB
564 break;
565 default:
566 goto bad_reg;
567 }
568 break;
569 case 14: /* Reserved. */
570 goto bad_reg;
571 case 15: /* Implementation specific. */
572 /* ??? Internal registers not implemented. */
573 break;
574 }
575 return;
576bad_reg:
577 /* ??? For debugging only. Should raise illegal instruction exception. */
578 cpu_abort(env, "Unimplemented cp15 register read\n");
579}
580
581uint32_t helper_get_cp15(CPUState *env, uint32_t insn)
582{
583 uint32_t op2;
584
585 op2 = (insn >> 5) & 7;
586 switch ((insn >> 16) & 0xf) {
587 case 0: /* ID codes. */
588 switch (op2) {
589 default: /* Device ID. */
40f137e1 590 return env->cp15.c0_cpuid;
b5ff1b31
FB
591 case 1: /* Cache Type. */
592 return 0x1dd20d2;
593 case 2: /* TCM status. */
594 return 0;
595 }
596 case 1: /* System configuration. */
597 switch (op2) {
598 case 0: /* Control register. */
599 return env->cp15.c1_sys;
600 case 1: /* Auxiliary control register. */
40f137e1
PB
601 if (arm_feature(env, ARM_FEATURE_AUXCR))
602 return 1;
603 goto bad_reg;
b5ff1b31
FB
604 case 2: /* Coprocessor access register. */
605 return env->cp15.c1_coproc;
606 default:
607 goto bad_reg;
608 }
609 case 2: /* MMU Page table control. */
610 return env->cp15.c2;
611 case 3: /* MMU Domain access control. */
612 return env->cp15.c3;
613 case 4: /* Reserved. */
614 goto bad_reg;
615 case 5: /* MMU Fault status. */
616 switch (op2) {
617 case 0:
618 return env->cp15.c5_data;
619 case 1:
620 return env->cp15.c5_insn;
621 default:
622 goto bad_reg;
623 }
624 case 6: /* MMU Fault address. */
625 switch (op2) {
626 case 0:
627 return env->cp15.c6_data;
628 case 1:
40f137e1
PB
629 /* Arm9 doesn't have an IFAR, but implementing it anyway shouldn't
630 do any harm. */
b5ff1b31
FB
631 return env->cp15.c6_insn;
632 default:
633 goto bad_reg;
634 }
635 case 7: /* Cache control. */
636 /* ??? This is for test, clean and invaidate operations that set the
637 Z flag. We can't represent N = Z = 1, so it also clears clears
638 the N flag. Oh well. */
639 env->NZF = 0;
640 return 0;
641 case 8: /* MMU TLB control. */
642 goto bad_reg;
643 case 9: /* Cache lockdown. */
644 switch (op2) {
645 case 0:
646 return env->cp15.c9_data;
647 case 1:
648 return env->cp15.c9_insn;
649 default:
650 goto bad_reg;
651 }
652 case 10: /* MMU TLB lockdown. */
653 /* ??? TLB lockdown not implemented. */
654 return 0;
655 case 11: /* TCM DMA control. */
656 case 12: /* Reserved. */
657 goto bad_reg;
658 case 13: /* Process ID. */
659 switch (op2) {
660 case 0:
661 return env->cp15.c13_fcse;
662 case 1:
663 return env->cp15.c13_context;
664 default:
665 goto bad_reg;
666 }
667 case 14: /* Reserved. */
668 goto bad_reg;
669 case 15: /* Implementation specific. */
670 /* ??? Internal registers not implemented. */
671 return 0;
672 }
673bad_reg:
674 /* ??? For debugging only. Should raise illegal instruction exception. */
675 cpu_abort(env, "Unimplemented cp15 register read\n");
676 return 0;
677}
678
679#endif