]> git.proxmox.com Git - mirror_qemu.git/blame - target-arm/helper.c
PCMCIA bus support. Parts of CF-ATA command set. Hitachi DSCM microdrive emulation.
[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
f3d6b95e
PB
8static inline void set_feature(CPUARMState *env, int feature)
9{
10 env->features |= 1u << feature;
11}
12
13static 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
40f137e1
PB
32void cpu_reset(CPUARMState *env)
33{
f3d6b95e
PB
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);
40f137e1
PB
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;
f3d6b95e 48 tlb_flush(env, 1);
40f137e1
PB
49}
50
51CPUARMState *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);
40f137e1
PB
60 return env;
61}
62
3371d272
PB
63struct arm_cpu_t {
64 uint32_t id;
65 const char *name;
66};
67
68static const struct arm_cpu_t arm_cpu_names[] = {
69 { ARM_CPUID_ARM926, "arm926"},
70 { ARM_CPUID_ARM1026, "arm1026"},
71 { 0, NULL}
72};
73
5adb4839
PB
74void 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
3371d272 84void cpu_arm_set_model(CPUARMState *env, const char *name)
40f137e1 85{
3371d272
PB
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 }
f3d6b95e 101 cpu_reset_model_id(env, id);
40f137e1
PB
102}
103
104void cpu_arm_close(CPUARMState *env)
105{
106 free(env);
107}
108
b5ff1b31
FB
109#if defined(CONFIG_USER_ONLY)
110
111void do_interrupt (CPUState *env)
112{
113 env->exception_index = -1;
114}
115
116int 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
9b3c35e0 129target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
b5ff1b31
FB
130{
131 return addr;
132}
133
134/* These should probably raise undefined insn exceptions. */
135void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val)
136{
137 cpu_abort(env, "cp15 insn %08x\n", insn);
138}
139
140uint32_t helper_get_cp15(CPUState *env, uint32_t insn)
141{
142 cpu_abort(env, "cp15 insn %08x\n", insn);
143 return 0;
144}
145
146void 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
8e71621f
PB
154extern int semihosting_enabled;
155
b5ff1b31
FB
156/* Map CPU modes onto saved register banks. */
157static 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
178void 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));
8637c67f 189 memcpy (env->regs + 8, env->usr_regs, 5 * sizeof(uint32_t));
b5ff1b31
FB
190 } else if (mode == ARM_CPU_MODE_FIQ) {
191 memcpy (env->usr_regs, env->regs + 8, 5 * sizeof(uint32_t));
8637c67f 192 memcpy (env->regs + 8, env->fiq_regs, 5 * sizeof(uint32_t));
b5ff1b31
FB
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. */
207void 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:
8e71621f
PB
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 }
b5ff1b31
FB
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:
06c949e6 249 case EXCP_BKPT:
b5ff1b31
FB
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);
6d7e6326 285 /* Switch to the new mode, and switch to Arm mode. */
b5ff1b31 286 /* ??? Thumb interrupt handlers not implemented. */
6d7e6326 287 env->uncached_cpsr = (env->uncached_cpsr & ~CPSR_M) | new_mode;
b5ff1b31 288 env->uncached_cpsr |= mask;
6d7e6326 289 env->thumb = 0;
b5ff1b31
FB
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. */
298static 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:
78600320 306 if (access_type == 1)
b5ff1b31
FB
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
330static 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. */
c73c3aa0
PB
375 if (type == 1) {
376 /* Coarse pagetable. */
377 table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc);
378 } else {
379 /* Fine pagetable. */
380 table = (desc & 0xfffff000) | ((address >> 8) & 0xffc);
381 }
b5ff1b31
FB
382 desc = ldl_phys(table);
383 switch (desc & 3) {
384 case 0: /* Page translation fault. */
385 code = 7;
386 goto do_fault;
387 case 1: /* 64k page. */
388 phys_addr = (desc & 0xffff0000) | (address & 0xffff);
389 ap = (desc >> (4 + ((address >> 13) & 6))) & 3;
390 break;
391 case 2: /* 4k page. */
392 phys_addr = (desc & 0xfffff000) | (address & 0xfff);
393 ap = (desc >> (4 + ((address >> 13) & 6))) & 3;
394 break;
395 case 3: /* 1k page. */
396 if (type == 1) {
397 /* Page translation fault. */
398 code = 7;
399 goto do_fault;
400 }
401 phys_addr = (desc & 0xfffffc00) | (address & 0x3ff);
402 ap = (desc >> 4) & 3;
403 break;
404 default:
405 /* Never happens, but compiler isn't smart enough to tell. */
406 abort();
407 }
408 code = 15;
409 }
410 *prot = check_ap(env, ap, domain, access_type, is_user);
411 if (!*prot) {
412 /* Access permission fault. */
413 goto do_fault;
414 }
415 *phys_ptr = phys_addr;
416 }
417 return 0;
418do_fault:
419 return code | (domain << 4);
420}
421
422int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address,
423 int access_type, int is_user, int is_softmmu)
424{
425 uint32_t phys_addr;
426 int prot;
427 int ret;
428
429 ret = get_phys_addr(env, address, access_type, is_user, &phys_addr, &prot);
430 if (ret == 0) {
431 /* Map a single [sub]page. */
432 phys_addr &= ~(uint32_t)0x3ff;
433 address &= ~(uint32_t)0x3ff;
434 return tlb_set_page (env, address, phys_addr, prot, is_user,
435 is_softmmu);
436 }
437
438 if (access_type == 2) {
439 env->cp15.c5_insn = ret;
440 env->cp15.c6_insn = address;
441 env->exception_index = EXCP_PREFETCH_ABORT;
442 } else {
443 env->cp15.c5_data = ret;
444 env->cp15.c6_data = address;
445 env->exception_index = EXCP_DATA_ABORT;
446 }
447 return 1;
448}
449
9b3c35e0 450target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
b5ff1b31
FB
451{
452 uint32_t phys_addr;
453 int prot;
454 int ret;
455
456 ret = get_phys_addr(env, addr, 0, 0, &phys_addr, &prot);
457
458 if (ret != 0)
459 return -1;
460
461 return phys_addr;
462}
463
464void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val)
465{
466 uint32_t op2;
467
468 op2 = (insn >> 5) & 7;
469 switch ((insn >> 16) & 0xf) {
470 case 0: /* ID codes. */
471 goto bad_reg;
472 case 1: /* System configuration. */
473 switch (op2) {
474 case 0:
475 env->cp15.c1_sys = val;
476 /* ??? Lots of these bits are not implemented. */
477 /* This may enable/disable the MMU, so do a TLB flush. */
478 tlb_flush(env, 1);
479 break;
480 case 2:
481 env->cp15.c1_coproc = val;
482 /* ??? Is this safe when called from within a TB? */
483 tb_flush(env);
484 default:
485 goto bad_reg;
486 }
487 break;
488 case 2: /* MMU Page table control. */
489 env->cp15.c2 = val;
490 break;
491 case 3: /* MMU Domain access control. */
492 env->cp15.c3 = val;
493 break;
494 case 4: /* Reserved. */
495 goto bad_reg;
496 case 5: /* MMU Fault status. */
497 switch (op2) {
498 case 0:
499 env->cp15.c5_data = val;
500 break;
501 case 1:
502 env->cp15.c5_insn = val;
503 break;
504 default:
505 goto bad_reg;
506 }
507 break;
508 case 6: /* MMU Fault address. */
509 switch (op2) {
510 case 0:
511 env->cp15.c6_data = val;
512 break;
513 case 1:
514 env->cp15.c6_insn = val;
515 break;
516 default:
517 goto bad_reg;
518 }
519 break;
520 case 7: /* Cache control. */
521 /* No cache, so nothing to do. */
522 break;
523 case 8: /* MMU TLB control. */
524 switch (op2) {
525 case 0: /* Invalidate all. */
526 tlb_flush(env, 0);
527 break;
528 case 1: /* Invalidate single TLB entry. */
529#if 0
530 /* ??? This is wrong for large pages and sections. */
531 /* As an ugly hack to make linux work we always flush a 4K
532 pages. */
533 val &= 0xfffff000;
534 tlb_flush_page(env, val);
535 tlb_flush_page(env, val + 0x400);
536 tlb_flush_page(env, val + 0x800);
537 tlb_flush_page(env, val + 0xc00);
538#else
539 tlb_flush(env, 1);
540#endif
541 break;
542 default:
543 goto bad_reg;
544 }
545 break;
546 case 9: /* Cache lockdown. */
547 switch (op2) {
548 case 0:
549 env->cp15.c9_data = val;
550 break;
551 case 1:
552 env->cp15.c9_insn = val;
553 break;
554 default:
555 goto bad_reg;
556 }
557 break;
558 case 10: /* MMU TLB lockdown. */
559 /* ??? TLB lockdown not implemented. */
560 break;
561 case 11: /* TCM DMA control. */
562 case 12: /* Reserved. */
563 goto bad_reg;
564 case 13: /* Process ID. */
565 switch (op2) {
566 case 0:
d07edbfa
PB
567 /* Unlike real hardware the qemu TLB uses virtual addresses,
568 not modified virtual addresses, so this causes a TLB flush.
569 */
570 if (env->cp15.c13_fcse != val)
571 tlb_flush(env, 1);
572 env->cp15.c13_fcse = val;
b5ff1b31
FB
573 break;
574 case 1:
d07edbfa
PB
575 /* This changes the ASID, so do a TLB flush. */
576 if (env->cp15.c13_context != val)
577 tlb_flush(env, 0);
578 env->cp15.c13_context = val;
b5ff1b31
FB
579 break;
580 default:
581 goto bad_reg;
582 }
583 break;
584 case 14: /* Reserved. */
585 goto bad_reg;
586 case 15: /* Implementation specific. */
587 /* ??? Internal registers not implemented. */
588 break;
589 }
590 return;
591bad_reg:
592 /* ??? For debugging only. Should raise illegal instruction exception. */
593 cpu_abort(env, "Unimplemented cp15 register read\n");
594}
595
596uint32_t helper_get_cp15(CPUState *env, uint32_t insn)
597{
598 uint32_t op2;
599
600 op2 = (insn >> 5) & 7;
601 switch ((insn >> 16) & 0xf) {
602 case 0: /* ID codes. */
603 switch (op2) {
604 default: /* Device ID. */
40f137e1 605 return env->cp15.c0_cpuid;
b5ff1b31
FB
606 case 1: /* Cache Type. */
607 return 0x1dd20d2;
608 case 2: /* TCM status. */
609 return 0;
610 }
611 case 1: /* System configuration. */
612 switch (op2) {
613 case 0: /* Control register. */
614 return env->cp15.c1_sys;
615 case 1: /* Auxiliary control register. */
40f137e1
PB
616 if (arm_feature(env, ARM_FEATURE_AUXCR))
617 return 1;
618 goto bad_reg;
b5ff1b31
FB
619 case 2: /* Coprocessor access register. */
620 return env->cp15.c1_coproc;
621 default:
622 goto bad_reg;
623 }
624 case 2: /* MMU Page table control. */
625 return env->cp15.c2;
626 case 3: /* MMU Domain access control. */
627 return env->cp15.c3;
628 case 4: /* Reserved. */
629 goto bad_reg;
630 case 5: /* MMU Fault status. */
631 switch (op2) {
632 case 0:
633 return env->cp15.c5_data;
634 case 1:
635 return env->cp15.c5_insn;
636 default:
637 goto bad_reg;
638 }
639 case 6: /* MMU Fault address. */
640 switch (op2) {
641 case 0:
642 return env->cp15.c6_data;
643 case 1:
40f137e1
PB
644 /* Arm9 doesn't have an IFAR, but implementing it anyway shouldn't
645 do any harm. */
b5ff1b31
FB
646 return env->cp15.c6_insn;
647 default:
648 goto bad_reg;
649 }
650 case 7: /* Cache control. */
651 /* ??? This is for test, clean and invaidate operations that set the
652 Z flag. We can't represent N = Z = 1, so it also clears clears
653 the N flag. Oh well. */
654 env->NZF = 0;
655 return 0;
656 case 8: /* MMU TLB control. */
657 goto bad_reg;
658 case 9: /* Cache lockdown. */
659 switch (op2) {
660 case 0:
661 return env->cp15.c9_data;
662 case 1:
663 return env->cp15.c9_insn;
664 default:
665 goto bad_reg;
666 }
667 case 10: /* MMU TLB lockdown. */
668 /* ??? TLB lockdown not implemented. */
669 return 0;
670 case 11: /* TCM DMA control. */
671 case 12: /* Reserved. */
672 goto bad_reg;
673 case 13: /* Process ID. */
674 switch (op2) {
675 case 0:
676 return env->cp15.c13_fcse;
677 case 1:
678 return env->cp15.c13_context;
679 default:
680 goto bad_reg;
681 }
682 case 14: /* Reserved. */
683 goto bad_reg;
684 case 15: /* Implementation specific. */
685 /* ??? Internal registers not implemented. */
686 return 0;
687 }
688bad_reg:
689 /* ??? For debugging only. Should raise illegal instruction exception. */
690 cpu_abort(env, "Unimplemented cp15 register read\n");
691 return 0;
692}
693
694#endif