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