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