Replace tabs by 8 spaces. No code change, by Herve Poussineau.
[qemu/dscho.git] / target-arm / helper.c
blobf1b170d030638708ba94179348561100c712018d
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
5 #include "cpu.h"
6 #include "exec-all.h"
8 static inline void set_feature(CPUARMState *env, int feature)
10 env->features |= 1u << feature;
13 static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
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 env->cp15.c0_cachetype = 0x1dd20d2;
21 env->cp15.c1_sys = 0x00090078;
22 break;
23 case ARM_CPUID_ARM946:
24 set_feature(env, ARM_FEATURE_MPU);
25 env->cp15.c0_cachetype = 0x0f004006;
26 env->cp15.c1_sys = 0x00000078;
27 break;
28 case ARM_CPUID_ARM1026:
29 set_feature(env, ARM_FEATURE_VFP);
30 set_feature(env, ARM_FEATURE_AUXCR);
31 env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0;
32 env->cp15.c0_cachetype = 0x1dd20d2;
33 env->cp15.c1_sys = 0x00090078;
34 break;
35 case ARM_CPUID_TI915T:
36 case ARM_CPUID_TI925T:
37 set_feature(env, ARM_FEATURE_OMAPCP);
38 env->cp15.c0_cpuid = ARM_CPUID_TI925T; /* Depends on wiring. */
39 env->cp15.c0_cachetype = 0x5109149;
40 env->cp15.c1_sys = 0x00000070;
41 env->cp15.c15_i_max = 0x000;
42 env->cp15.c15_i_min = 0xff0;
43 break;
44 case ARM_CPUID_PXA250:
45 case ARM_CPUID_PXA255:
46 case ARM_CPUID_PXA260:
47 case ARM_CPUID_PXA261:
48 case ARM_CPUID_PXA262:
49 set_feature(env, ARM_FEATURE_XSCALE);
50 /* JTAG_ID is ((id << 28) | 0x09265013) */
51 env->cp15.c0_cachetype = 0xd172172;
52 env->cp15.c1_sys = 0x00000078;
53 break;
54 case ARM_CPUID_PXA270_A0:
55 case ARM_CPUID_PXA270_A1:
56 case ARM_CPUID_PXA270_B0:
57 case ARM_CPUID_PXA270_B1:
58 case ARM_CPUID_PXA270_C0:
59 case ARM_CPUID_PXA270_C5:
60 set_feature(env, ARM_FEATURE_XSCALE);
61 /* JTAG_ID is ((id << 28) | 0x09265013) */
62 set_feature(env, ARM_FEATURE_IWMMXT);
63 env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q';
64 env->cp15.c0_cachetype = 0xd172172;
65 env->cp15.c1_sys = 0x00000078;
66 break;
67 default:
68 cpu_abort(env, "Bad CPU ID: %x\n", id);
69 break;
73 void cpu_reset(CPUARMState *env)
75 uint32_t id;
76 id = env->cp15.c0_cpuid;
77 memset(env, 0, offsetof(CPUARMState, breakpoints));
78 if (id)
79 cpu_reset_model_id(env, id);
80 #if defined (CONFIG_USER_ONLY)
81 env->uncached_cpsr = ARM_CPU_MODE_USR;
82 env->vfp.xregs[ARM_VFP_FPEXC] = 1 << 30;
83 #else
84 /* SVC mode with interrupts disabled. */
85 env->uncached_cpsr = ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I;
86 env->vfp.xregs[ARM_VFP_FPEXC] = 0;
87 #endif
88 env->regs[15] = 0;
89 tlb_flush(env, 1);
92 CPUARMState *cpu_arm_init(void)
94 CPUARMState *env;
96 env = qemu_mallocz(sizeof(CPUARMState));
97 if (!env)
98 return NULL;
99 cpu_exec_init(env);
100 cpu_reset(env);
101 return env;
104 struct arm_cpu_t {
105 uint32_t id;
106 const char *name;
109 static const struct arm_cpu_t arm_cpu_names[] = {
110 { ARM_CPUID_ARM926, "arm926"},
111 { ARM_CPUID_ARM946, "arm946"},
112 { ARM_CPUID_ARM1026, "arm1026"},
113 { ARM_CPUID_TI925T, "ti925t" },
114 { ARM_CPUID_PXA250, "pxa250" },
115 { ARM_CPUID_PXA255, "pxa255" },
116 { ARM_CPUID_PXA260, "pxa260" },
117 { ARM_CPUID_PXA261, "pxa261" },
118 { ARM_CPUID_PXA262, "pxa262" },
119 { ARM_CPUID_PXA270, "pxa270" },
120 { ARM_CPUID_PXA270_A0, "pxa270-a0" },
121 { ARM_CPUID_PXA270_A1, "pxa270-a1" },
122 { ARM_CPUID_PXA270_B0, "pxa270-b0" },
123 { ARM_CPUID_PXA270_B1, "pxa270-b1" },
124 { ARM_CPUID_PXA270_C0, "pxa270-c0" },
125 { ARM_CPUID_PXA270_C5, "pxa270-c5" },
126 { 0, NULL}
129 void arm_cpu_list(void)
131 int i;
133 printf ("Available CPUs:\n");
134 for (i = 0; arm_cpu_names[i].name; i++) {
135 printf(" %s\n", arm_cpu_names[i].name);
139 void cpu_arm_set_model(CPUARMState *env, const char *name)
141 int i;
142 uint32_t id;
144 id = 0;
145 i = 0;
146 for (i = 0; arm_cpu_names[i].name; i++) {
147 if (strcmp(name, arm_cpu_names[i].name) == 0) {
148 id = arm_cpu_names[i].id;
149 break;
152 if (!id) {
153 cpu_abort(env, "Unknown CPU '%s'", name);
154 return;
156 cpu_reset_model_id(env, id);
159 void cpu_arm_close(CPUARMState *env)
161 free(env);
164 #if defined(CONFIG_USER_ONLY)
166 void do_interrupt (CPUState *env)
168 env->exception_index = -1;
171 int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
172 int is_user, int is_softmmu)
174 if (rw == 2) {
175 env->exception_index = EXCP_PREFETCH_ABORT;
176 env->cp15.c6_insn = address;
177 } else {
178 env->exception_index = EXCP_DATA_ABORT;
179 env->cp15.c6_data = address;
181 return 1;
184 target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
186 return addr;
189 /* These should probably raise undefined insn exceptions. */
190 void helper_set_cp(CPUState *env, uint32_t insn, uint32_t val)
192 int op1 = (insn >> 8) & 0xf;
193 cpu_abort(env, "cp%i insn %08x\n", op1, insn);
194 return;
197 uint32_t helper_get_cp(CPUState *env, uint32_t insn)
199 int op1 = (insn >> 8) & 0xf;
200 cpu_abort(env, "cp%i insn %08x\n", op1, insn);
201 return 0;
204 void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val)
206 cpu_abort(env, "cp15 insn %08x\n", insn);
209 uint32_t helper_get_cp15(CPUState *env, uint32_t insn)
211 cpu_abort(env, "cp15 insn %08x\n", insn);
212 return 0;
215 void switch_mode(CPUState *env, int mode)
217 if (mode != ARM_CPU_MODE_USR)
218 cpu_abort(env, "Tried to switch out of user mode\n");
221 #else
223 extern int semihosting_enabled;
225 /* Map CPU modes onto saved register banks. */
226 static inline int bank_number (int mode)
228 switch (mode) {
229 case ARM_CPU_MODE_USR:
230 case ARM_CPU_MODE_SYS:
231 return 0;
232 case ARM_CPU_MODE_SVC:
233 return 1;
234 case ARM_CPU_MODE_ABT:
235 return 2;
236 case ARM_CPU_MODE_UND:
237 return 3;
238 case ARM_CPU_MODE_IRQ:
239 return 4;
240 case ARM_CPU_MODE_FIQ:
241 return 5;
243 cpu_abort(cpu_single_env, "Bad mode %x\n", mode);
244 return -1;
247 void switch_mode(CPUState *env, int mode)
249 int old_mode;
250 int i;
252 old_mode = env->uncached_cpsr & CPSR_M;
253 if (mode == old_mode)
254 return;
256 if (old_mode == ARM_CPU_MODE_FIQ) {
257 memcpy (env->fiq_regs, env->regs + 8, 5 * sizeof(uint32_t));
258 memcpy (env->regs + 8, env->usr_regs, 5 * sizeof(uint32_t));
259 } else if (mode == ARM_CPU_MODE_FIQ) {
260 memcpy (env->usr_regs, env->regs + 8, 5 * sizeof(uint32_t));
261 memcpy (env->regs + 8, env->fiq_regs, 5 * sizeof(uint32_t));
264 i = bank_number(old_mode);
265 env->banked_r13[i] = env->regs[13];
266 env->banked_r14[i] = env->regs[14];
267 env->banked_spsr[i] = env->spsr;
269 i = bank_number(mode);
270 env->regs[13] = env->banked_r13[i];
271 env->regs[14] = env->banked_r14[i];
272 env->spsr = env->banked_spsr[i];
275 /* Handle a CPU exception. */
276 void do_interrupt(CPUARMState *env)
278 uint32_t addr;
279 uint32_t mask;
280 int new_mode;
281 uint32_t offset;
283 /* TODO: Vectored interrupt controller. */
284 switch (env->exception_index) {
285 case EXCP_UDEF:
286 new_mode = ARM_CPU_MODE_UND;
287 addr = 0x04;
288 mask = CPSR_I;
289 if (env->thumb)
290 offset = 2;
291 else
292 offset = 4;
293 break;
294 case EXCP_SWI:
295 if (semihosting_enabled) {
296 /* Check for semihosting interrupt. */
297 if (env->thumb) {
298 mask = lduw_code(env->regs[15] - 2) & 0xff;
299 } else {
300 mask = ldl_code(env->regs[15] - 4) & 0xffffff;
302 /* Only intercept calls from privileged modes, to provide some
303 semblance of security. */
304 if (((mask == 0x123456 && !env->thumb)
305 || (mask == 0xab && env->thumb))
306 && (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR) {
307 env->regs[0] = do_arm_semihosting(env);
308 return;
311 new_mode = ARM_CPU_MODE_SVC;
312 addr = 0x08;
313 mask = CPSR_I;
314 /* The PC already points to the next instructon. */
315 offset = 0;
316 break;
317 case EXCP_PREFETCH_ABORT:
318 case EXCP_BKPT:
319 new_mode = ARM_CPU_MODE_ABT;
320 addr = 0x0c;
321 mask = CPSR_A | CPSR_I;
322 offset = 4;
323 break;
324 case EXCP_DATA_ABORT:
325 new_mode = ARM_CPU_MODE_ABT;
326 addr = 0x10;
327 mask = CPSR_A | CPSR_I;
328 offset = 8;
329 break;
330 case EXCP_IRQ:
331 new_mode = ARM_CPU_MODE_IRQ;
332 addr = 0x18;
333 /* Disable IRQ and imprecise data aborts. */
334 mask = CPSR_A | CPSR_I;
335 offset = 4;
336 break;
337 case EXCP_FIQ:
338 new_mode = ARM_CPU_MODE_FIQ;
339 addr = 0x1c;
340 /* Disable FIQ, IRQ and imprecise data aborts. */
341 mask = CPSR_A | CPSR_I | CPSR_F;
342 offset = 4;
343 break;
344 default:
345 cpu_abort(env, "Unhandled exception 0x%x\n", env->exception_index);
346 return; /* Never happens. Keep compiler happy. */
348 /* High vectors. */
349 if (env->cp15.c1_sys & (1 << 13)) {
350 addr += 0xffff0000;
352 switch_mode (env, new_mode);
353 env->spsr = cpsr_read(env);
354 /* Switch to the new mode, and switch to Arm mode. */
355 /* ??? Thumb interrupt handlers not implemented. */
356 env->uncached_cpsr = (env->uncached_cpsr & ~CPSR_M) | new_mode;
357 env->uncached_cpsr |= mask;
358 env->thumb = 0;
359 env->regs[14] = env->regs[15] + offset;
360 env->regs[15] = addr;
361 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
364 /* Check section/page access permissions.
365 Returns the page protection flags, or zero if the access is not
366 permitted. */
367 static inline int check_ap(CPUState *env, int ap, int domain, int access_type,
368 int is_user)
370 if (domain == 3)
371 return PAGE_READ | PAGE_WRITE;
373 switch (ap) {
374 case 0:
375 if (access_type == 1)
376 return 0;
377 switch ((env->cp15.c1_sys >> 8) & 3) {
378 case 1:
379 return is_user ? 0 : PAGE_READ;
380 case 2:
381 return PAGE_READ;
382 default:
383 return 0;
385 case 1:
386 return is_user ? 0 : PAGE_READ | PAGE_WRITE;
387 case 2:
388 if (is_user)
389 return (access_type == 1) ? 0 : PAGE_READ;
390 else
391 return PAGE_READ | PAGE_WRITE;
392 case 3:
393 return PAGE_READ | PAGE_WRITE;
394 default:
395 abort();
399 static int get_phys_addr(CPUState *env, uint32_t address, int access_type,
400 int is_user, uint32_t *phys_ptr, int *prot)
402 int code;
403 uint32_t table;
404 uint32_t desc;
405 int type;
406 int ap;
407 int domain;
408 uint32_t phys_addr;
410 /* Fast Context Switch Extension. */
411 if (address < 0x02000000)
412 address += env->cp15.c13_fcse;
414 if ((env->cp15.c1_sys & 1) == 0) {
415 /* MMU/MPU disabled. */
416 *phys_ptr = address;
417 *prot = PAGE_READ | PAGE_WRITE;
418 } else if (arm_feature(env, ARM_FEATURE_MPU)) {
419 int n;
420 uint32_t mask;
421 uint32_t base;
423 *phys_ptr = address;
424 for (n = 7; n >= 0; n--) {
425 base = env->cp15.c6_region[n];
426 if ((base & 1) == 0)
427 continue;
428 mask = 1 << ((base >> 1) & 0x1f);
429 /* Keep this shift separate from the above to avoid an
430 (undefined) << 32. */
431 mask = (mask << 1) - 1;
432 if (((base ^ address) & ~mask) == 0)
433 break;
435 if (n < 0)
436 return 2;
438 if (access_type == 2) {
439 mask = env->cp15.c5_insn;
440 } else {
441 mask = env->cp15.c5_data;
443 mask = (mask >> (n * 4)) & 0xf;
444 switch (mask) {
445 case 0:
446 return 1;
447 case 1:
448 if (is_user)
449 return 1;
450 *prot = PAGE_READ | PAGE_WRITE;
451 break;
452 case 2:
453 *prot = PAGE_READ;
454 if (!is_user)
455 *prot |= PAGE_WRITE;
456 break;
457 case 3:
458 *prot = PAGE_READ | PAGE_WRITE;
459 break;
460 case 5:
461 if (is_user)
462 return 1;
463 *prot = PAGE_READ;
464 break;
465 case 6:
466 *prot = PAGE_READ;
467 break;
468 default:
469 /* Bad permission. */
470 return 1;
472 } else {
473 /* Pagetable walk. */
474 /* Lookup l1 descriptor. */
475 table = (env->cp15.c2_base & 0xffffc000) | ((address >> 18) & 0x3ffc);
476 desc = ldl_phys(table);
477 type = (desc & 3);
478 domain = (env->cp15.c3 >> ((desc >> 4) & 0x1e)) & 3;
479 if (type == 0) {
480 /* Secton translation fault. */
481 code = 5;
482 goto do_fault;
484 if (domain == 0 || domain == 2) {
485 if (type == 2)
486 code = 9; /* Section domain fault. */
487 else
488 code = 11; /* Page domain fault. */
489 goto do_fault;
491 if (type == 2) {
492 /* 1Mb section. */
493 phys_addr = (desc & 0xfff00000) | (address & 0x000fffff);
494 ap = (desc >> 10) & 3;
495 code = 13;
496 } else {
497 /* Lookup l2 entry. */
498 if (type == 1) {
499 /* Coarse pagetable. */
500 table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc);
501 } else {
502 /* Fine pagetable. */
503 table = (desc & 0xfffff000) | ((address >> 8) & 0xffc);
505 desc = ldl_phys(table);
506 switch (desc & 3) {
507 case 0: /* Page translation fault. */
508 code = 7;
509 goto do_fault;
510 case 1: /* 64k page. */
511 phys_addr = (desc & 0xffff0000) | (address & 0xffff);
512 ap = (desc >> (4 + ((address >> 13) & 6))) & 3;
513 break;
514 case 2: /* 4k page. */
515 phys_addr = (desc & 0xfffff000) | (address & 0xfff);
516 ap = (desc >> (4 + ((address >> 13) & 6))) & 3;
517 break;
518 case 3: /* 1k page. */
519 if (type == 1) {
520 if (arm_feature(env, ARM_FEATURE_XSCALE))
521 phys_addr = (desc & 0xfffff000) | (address & 0xfff);
522 else {
523 /* Page translation fault. */
524 code = 7;
525 goto do_fault;
527 } else
528 phys_addr = (desc & 0xfffffc00) | (address & 0x3ff);
529 ap = (desc >> 4) & 3;
530 break;
531 default:
532 /* Never happens, but compiler isn't smart enough to tell. */
533 abort();
535 code = 15;
537 *prot = check_ap(env, ap, domain, access_type, is_user);
538 if (!*prot) {
539 /* Access permission fault. */
540 goto do_fault;
542 *phys_ptr = phys_addr;
544 return 0;
545 do_fault:
546 return code | (domain << 4);
549 int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address,
550 int access_type, int is_user, int is_softmmu)
552 uint32_t phys_addr;
553 int prot;
554 int ret;
556 ret = get_phys_addr(env, address, access_type, is_user, &phys_addr, &prot);
557 if (ret == 0) {
558 /* Map a single [sub]page. */
559 phys_addr &= ~(uint32_t)0x3ff;
560 address &= ~(uint32_t)0x3ff;
561 return tlb_set_page (env, address, phys_addr, prot, is_user,
562 is_softmmu);
565 if (access_type == 2) {
566 env->cp15.c5_insn = ret;
567 env->cp15.c6_insn = address;
568 env->exception_index = EXCP_PREFETCH_ABORT;
569 } else {
570 env->cp15.c5_data = ret;
571 env->cp15.c6_data = address;
572 env->exception_index = EXCP_DATA_ABORT;
574 return 1;
577 target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
579 uint32_t phys_addr;
580 int prot;
581 int ret;
583 ret = get_phys_addr(env, addr, 0, 0, &phys_addr, &prot);
585 if (ret != 0)
586 return -1;
588 return phys_addr;
591 void helper_set_cp(CPUState *env, uint32_t insn, uint32_t val)
593 int cp_num = (insn >> 8) & 0xf;
594 int cp_info = (insn >> 5) & 7;
595 int src = (insn >> 16) & 0xf;
596 int operand = insn & 0xf;
598 if (env->cp[cp_num].cp_write)
599 env->cp[cp_num].cp_write(env->cp[cp_num].opaque,
600 cp_info, src, operand, val);
603 uint32_t helper_get_cp(CPUState *env, uint32_t insn)
605 int cp_num = (insn >> 8) & 0xf;
606 int cp_info = (insn >> 5) & 7;
607 int dest = (insn >> 16) & 0xf;
608 int operand = insn & 0xf;
610 if (env->cp[cp_num].cp_read)
611 return env->cp[cp_num].cp_read(env->cp[cp_num].opaque,
612 cp_info, dest, operand);
613 return 0;
616 /* Return basic MPU access permission bits. */
617 static uint32_t simple_mpu_ap_bits(uint32_t val)
619 uint32_t ret;
620 uint32_t mask;
621 int i;
622 ret = 0;
623 mask = 3;
624 for (i = 0; i < 16; i += 2) {
625 ret |= (val >> i) & mask;
626 mask <<= 2;
628 return ret;
631 /* Pad basic MPU access permission bits to extended format. */
632 static uint32_t extended_mpu_ap_bits(uint32_t val)
634 uint32_t ret;
635 uint32_t mask;
636 int i;
637 ret = 0;
638 mask = 3;
639 for (i = 0; i < 16; i += 2) {
640 ret |= (val & mask) << i;
641 mask <<= 2;
643 return ret;
646 void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val)
648 uint32_t op2;
649 uint32_t crm;
651 op2 = (insn >> 5) & 7;
652 crm = insn & 0xf;
653 switch ((insn >> 16) & 0xf) {
654 case 0: /* ID codes. */
655 if (arm_feature(env, ARM_FEATURE_XSCALE))
656 break;
657 if (arm_feature(env, ARM_FEATURE_OMAPCP))
658 break;
659 goto bad_reg;
660 case 1: /* System configuration. */
661 if (arm_feature(env, ARM_FEATURE_OMAPCP))
662 op2 = 0;
663 switch (op2) {
664 case 0:
665 if (!arm_feature(env, ARM_FEATURE_XSCALE) || crm == 0)
666 env->cp15.c1_sys = val;
667 /* ??? Lots of these bits are not implemented. */
668 /* This may enable/disable the MMU, so do a TLB flush. */
669 tlb_flush(env, 1);
670 break;
671 case 1:
672 if (arm_feature(env, ARM_FEATURE_XSCALE)) {
673 env->cp15.c1_xscaleauxcr = val;
674 break;
676 goto bad_reg;
677 case 2:
678 if (arm_feature(env, ARM_FEATURE_XSCALE))
679 goto bad_reg;
680 env->cp15.c1_coproc = val;
681 /* ??? Is this safe when called from within a TB? */
682 tb_flush(env);
683 break;
684 default:
685 goto bad_reg;
687 break;
688 case 2: /* MMU Page table control / MPU cache control. */
689 if (arm_feature(env, ARM_FEATURE_MPU)) {
690 switch (op2) {
691 case 0:
692 env->cp15.c2_data = val;
693 break;
694 case 1:
695 env->cp15.c2_insn = val;
696 break;
697 default:
698 goto bad_reg;
700 } else {
701 env->cp15.c2_base = val;
703 break;
704 case 3: /* MMU Domain access control / MPU write buffer control. */
705 env->cp15.c3 = val;
706 break;
707 case 4: /* Reserved. */
708 goto bad_reg;
709 case 5: /* MMU Fault status / MPU access permission. */
710 if (arm_feature(env, ARM_FEATURE_OMAPCP))
711 op2 = 0;
712 switch (op2) {
713 case 0:
714 if (arm_feature(env, ARM_FEATURE_MPU))
715 val = extended_mpu_ap_bits(val);
716 env->cp15.c5_data = val;
717 break;
718 case 1:
719 if (arm_feature(env, ARM_FEATURE_MPU))
720 val = extended_mpu_ap_bits(val);
721 env->cp15.c5_insn = val;
722 break;
723 case 2:
724 if (!arm_feature(env, ARM_FEATURE_MPU))
725 goto bad_reg;
726 env->cp15.c5_data = val;
727 break;
728 case 3:
729 if (!arm_feature(env, ARM_FEATURE_MPU))
730 goto bad_reg;
731 env->cp15.c5_insn = val;
732 break;
733 default:
734 goto bad_reg;
736 break;
737 case 6: /* MMU Fault address / MPU base/size. */
738 if (arm_feature(env, ARM_FEATURE_MPU)) {
739 if (crm >= 8)
740 goto bad_reg;
741 env->cp15.c6_region[crm] = val;
742 } else {
743 if (arm_feature(env, ARM_FEATURE_OMAPCP))
744 op2 = 0;
745 switch (op2) {
746 case 0:
747 env->cp15.c6_data = val;
748 break;
749 case 1:
750 env->cp15.c6_insn = val;
751 break;
752 default:
753 goto bad_reg;
756 break;
757 case 7: /* Cache control. */
758 env->cp15.c15_i_max = 0x000;
759 env->cp15.c15_i_min = 0xff0;
760 /* No cache, so nothing to do. */
761 break;
762 case 8: /* MMU TLB control. */
763 switch (op2) {
764 case 0: /* Invalidate all. */
765 tlb_flush(env, 0);
766 break;
767 case 1: /* Invalidate single TLB entry. */
768 #if 0
769 /* ??? This is wrong for large pages and sections. */
770 /* As an ugly hack to make linux work we always flush a 4K
771 pages. */
772 val &= 0xfffff000;
773 tlb_flush_page(env, val);
774 tlb_flush_page(env, val + 0x400);
775 tlb_flush_page(env, val + 0x800);
776 tlb_flush_page(env, val + 0xc00);
777 #else
778 tlb_flush(env, 1);
779 #endif
780 break;
781 default:
782 goto bad_reg;
784 break;
785 case 9:
786 if (arm_feature(env, ARM_FEATURE_OMAPCP))
787 break;
788 switch (crm) {
789 case 0: /* Cache lockdown. */
790 switch (op2) {
791 case 0:
792 env->cp15.c9_data = val;
793 break;
794 case 1:
795 env->cp15.c9_insn = val;
796 break;
797 default:
798 goto bad_reg;
800 break;
801 case 1: /* TCM memory region registers. */
802 /* Not implemented. */
803 goto bad_reg;
804 default:
805 goto bad_reg;
807 break;
808 case 10: /* MMU TLB lockdown. */
809 /* ??? TLB lockdown not implemented. */
810 break;
811 case 12: /* Reserved. */
812 goto bad_reg;
813 case 13: /* Process ID. */
814 switch (op2) {
815 case 0:
816 if (!arm_feature(env, ARM_FEATURE_MPU))
817 goto bad_reg;
818 /* Unlike real hardware the qemu TLB uses virtual addresses,
819 not modified virtual addresses, so this causes a TLB flush.
821 if (env->cp15.c13_fcse != val)
822 tlb_flush(env, 1);
823 env->cp15.c13_fcse = val;
824 break;
825 case 1:
826 /* This changes the ASID, so do a TLB flush. */
827 if (env->cp15.c13_context != val
828 && !arm_feature(env, ARM_FEATURE_MPU))
829 tlb_flush(env, 0);
830 env->cp15.c13_context = val;
831 break;
832 default:
833 goto bad_reg;
835 break;
836 case 14: /* Reserved. */
837 goto bad_reg;
838 case 15: /* Implementation specific. */
839 if (arm_feature(env, ARM_FEATURE_XSCALE)) {
840 if (op2 == 0 && crm == 1) {
841 if (env->cp15.c15_cpar != (val & 0x3fff)) {
842 /* Changes cp0 to cp13 behavior, so needs a TB flush. */
843 tb_flush(env);
844 env->cp15.c15_cpar = val & 0x3fff;
846 break;
848 goto bad_reg;
850 if (arm_feature(env, ARM_FEATURE_OMAPCP)) {
851 switch (crm) {
852 case 0:
853 break;
854 case 1: /* Set TI925T configuration. */
855 env->cp15.c15_ticonfig = val & 0xe7;
856 env->cp15.c0_cpuid = (val & (1 << 5)) ? /* OS_TYPE bit */
857 ARM_CPUID_TI915T : ARM_CPUID_TI925T;
858 break;
859 case 2: /* Set I_max. */
860 env->cp15.c15_i_max = val;
861 break;
862 case 3: /* Set I_min. */
863 env->cp15.c15_i_min = val;
864 break;
865 case 4: /* Set thread-ID. */
866 env->cp15.c15_threadid = val & 0xffff;
867 break;
868 case 8: /* Wait-for-interrupt (deprecated). */
869 cpu_interrupt(env, CPU_INTERRUPT_HALT);
870 break;
871 default:
872 goto bad_reg;
875 break;
877 return;
878 bad_reg:
879 /* ??? For debugging only. Should raise illegal instruction exception. */
880 cpu_abort(env, "Unimplemented cp15 register write\n");
883 uint32_t helper_get_cp15(CPUState *env, uint32_t insn)
885 uint32_t op2;
886 uint32_t crm;
888 op2 = (insn >> 5) & 7;
889 crm = insn & 0xf;
890 switch ((insn >> 16) & 0xf) {
891 case 0: /* ID codes. */
892 switch (op2) {
893 default: /* Device ID. */
894 return env->cp15.c0_cpuid;
895 case 1: /* Cache Type. */
896 return env->cp15.c0_cachetype;
897 case 2: /* TCM status. */
898 if (arm_feature(env, ARM_FEATURE_XSCALE))
899 goto bad_reg;
900 return 0;
902 case 1: /* System configuration. */
903 if (arm_feature(env, ARM_FEATURE_OMAPCP))
904 op2 = 0;
905 switch (op2) {
906 case 0: /* Control register. */
907 return env->cp15.c1_sys;
908 case 1: /* Auxiliary control register. */
909 if (arm_feature(env, ARM_FEATURE_AUXCR))
910 return 1;
911 if (arm_feature(env, ARM_FEATURE_XSCALE))
912 return env->cp15.c1_xscaleauxcr;
913 goto bad_reg;
914 case 2: /* Coprocessor access register. */
915 if (arm_feature(env, ARM_FEATURE_XSCALE))
916 goto bad_reg;
917 return env->cp15.c1_coproc;
918 default:
919 goto bad_reg;
921 case 2: /* MMU Page table control / MPU cache control. */
922 if (arm_feature(env, ARM_FEATURE_MPU)) {
923 switch (op2) {
924 case 0:
925 return env->cp15.c2_data;
926 break;
927 case 1:
928 return env->cp15.c2_insn;
929 break;
930 default:
931 goto bad_reg;
933 } else {
934 return env->cp15.c2_base;
936 case 3: /* MMU Domain access control / MPU write buffer control. */
937 return env->cp15.c3;
938 case 4: /* Reserved. */
939 goto bad_reg;
940 case 5: /* MMU Fault status / MPU access permission. */
941 if (arm_feature(env, ARM_FEATURE_OMAPCP))
942 op2 = 0;
943 switch (op2) {
944 case 0:
945 if (arm_feature(env, ARM_FEATURE_MPU))
946 return simple_mpu_ap_bits(env->cp15.c5_data);
947 return env->cp15.c5_data;
948 case 1:
949 if (arm_feature(env, ARM_FEATURE_MPU))
950 return simple_mpu_ap_bits(env->cp15.c5_data);
951 return env->cp15.c5_insn;
952 case 2:
953 if (!arm_feature(env, ARM_FEATURE_MPU))
954 goto bad_reg;
955 return env->cp15.c5_data;
956 case 3:
957 if (!arm_feature(env, ARM_FEATURE_MPU))
958 goto bad_reg;
959 return env->cp15.c5_insn;
960 default:
961 goto bad_reg;
963 case 6: /* MMU Fault address / MPU base/size. */
964 if (arm_feature(env, ARM_FEATURE_MPU)) {
965 int n;
966 n = (insn & 0xf);
967 if (n >= 8)
968 goto bad_reg;
969 return env->cp15.c6_region[n];
970 } else {
971 if (arm_feature(env, ARM_FEATURE_OMAPCP))
972 op2 = 0;
973 switch (op2) {
974 case 0:
975 return env->cp15.c6_data;
976 case 1:
977 /* Arm9 doesn't have an IFAR, but implementing it anyway
978 shouldn't do any harm. */
979 return env->cp15.c6_insn;
980 default:
981 goto bad_reg;
984 case 7: /* Cache control. */
985 /* ??? This is for test, clean and invaidate operations that set the
986 Z flag. We can't represent N = Z = 1, so it also clears
987 the N flag. Oh well. */
988 env->NZF = 0;
989 return 0;
990 case 8: /* MMU TLB control. */
991 goto bad_reg;
992 case 9: /* Cache lockdown. */
993 if (arm_feature(env, ARM_FEATURE_OMAPCP))
994 return 0;
995 switch (op2) {
996 case 0:
997 return env->cp15.c9_data;
998 case 1:
999 return env->cp15.c9_insn;
1000 default:
1001 goto bad_reg;
1003 case 10: /* MMU TLB lockdown. */
1004 /* ??? TLB lockdown not implemented. */
1005 return 0;
1006 case 11: /* TCM DMA control. */
1007 case 12: /* Reserved. */
1008 goto bad_reg;
1009 case 13: /* Process ID. */
1010 switch (op2) {
1011 case 0:
1012 return env->cp15.c13_fcse;
1013 case 1:
1014 return env->cp15.c13_context;
1015 default:
1016 goto bad_reg;
1018 case 14: /* Reserved. */
1019 goto bad_reg;
1020 case 15: /* Implementation specific. */
1021 if (arm_feature(env, ARM_FEATURE_XSCALE)) {
1022 if (op2 == 0 && crm == 1)
1023 return env->cp15.c15_cpar;
1025 goto bad_reg;
1027 if (arm_feature(env, ARM_FEATURE_OMAPCP)) {
1028 switch (crm) {
1029 case 0:
1030 return 0;
1031 case 1: /* Read TI925T configuration. */
1032 return env->cp15.c15_ticonfig;
1033 case 2: /* Read I_max. */
1034 return env->cp15.c15_i_max;
1035 case 3: /* Read I_min. */
1036 return env->cp15.c15_i_min;
1037 case 4: /* Read thread-ID. */
1038 return env->cp15.c15_threadid;
1039 case 8: /* TI925T_status */
1040 return 0;
1042 goto bad_reg;
1044 return 0;
1046 bad_reg:
1047 /* ??? For debugging only. Should raise illegal instruction exception. */
1048 cpu_abort(env, "Unimplemented cp15 register read\n");
1049 return 0;
1052 void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
1053 ARMReadCPFunc *cp_read, ARMWriteCPFunc *cp_write,
1054 void *opaque)
1056 if (cpnum < 0 || cpnum > 14) {
1057 cpu_abort(env, "Bad coprocessor number: %i\n", cpnum);
1058 return;
1061 env->cp[cpnum].cp_read = cp_read;
1062 env->cp[cpnum].cp_write = cp_write;
1063 env->cp[cpnum].opaque = opaque;
1066 #endif