8 void cpu_reset(CPUARMState
*env
)
10 #if defined (CONFIG_USER_ONLY)
11 env
->uncached_cpsr
= ARM_CPU_MODE_USR
;
12 env
->vfp
.xregs
[ARM_VFP_FPEXC
] = 1 << 30;
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;
21 CPUARMState
*cpu_arm_init(void)
25 env
= qemu_mallocz(sizeof(CPUARMState
));
34 static inline void set_feature(CPUARMState
*env
, int feature
)
36 env
->features
|= 1u << feature
;
39 void cpu_arm_set_model(CPUARMState
*env
, uint32_t id
)
41 env
->cp15
.c0_cpuid
= id
;
43 case ARM_CPUID_ARM926
:
44 set_feature(env
, ARM_FEATURE_VFP
);
45 env
->vfp
.xregs
[ARM_VFP_FPSID
] = 0x41011090;
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;
53 cpu_abort(env
, "Bad CPU ID: %x\n", id
);
58 void cpu_arm_close(CPUARMState
*env
)
63 #if defined(CONFIG_USER_ONLY)
65 void do_interrupt (CPUState
*env
)
67 env
->exception_index
= -1;
70 int cpu_arm_handle_mmu_fault (CPUState
*env
, target_ulong address
, int rw
,
71 int is_user
, int is_softmmu
)
74 env
->exception_index
= EXCP_PREFETCH_ABORT
;
75 env
->cp15
.c6_insn
= address
;
77 env
->exception_index
= EXCP_DATA_ABORT
;
78 env
->cp15
.c6_data
= address
;
83 target_ulong
cpu_get_phys_page_debug(CPUState
*env
, target_ulong addr
)
88 /* These should probably raise undefined insn exceptions. */
89 void helper_set_cp15(CPUState
*env
, uint32_t insn
, uint32_t val
)
91 cpu_abort(env
, "cp15 insn %08x\n", insn
);
94 uint32_t helper_get_cp15(CPUState
*env
, uint32_t insn
)
96 cpu_abort(env
, "cp15 insn %08x\n", insn
);
100 void switch_mode(CPUState
*env
, int mode
)
102 if (mode
!= ARM_CPU_MODE_USR
)
103 cpu_abort(env
, "Tried to switch out of user mode\n");
108 /* Map CPU modes onto saved register banks. */
109 static inline int bank_number (int mode
)
112 case ARM_CPU_MODE_USR
:
113 case ARM_CPU_MODE_SYS
:
115 case ARM_CPU_MODE_SVC
:
117 case ARM_CPU_MODE_ABT
:
119 case ARM_CPU_MODE_UND
:
121 case ARM_CPU_MODE_IRQ
:
123 case ARM_CPU_MODE_FIQ
:
126 cpu_abort(cpu_single_env
, "Bad mode %x\n", mode
);
130 void switch_mode(CPUState
*env
, int mode
)
135 old_mode
= env
->uncached_cpsr
& CPSR_M
;
136 if (mode
== old_mode
)
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));
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
;
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
];
158 /* Handle a CPU exception. */
159 void do_interrupt(CPUARMState
*env
)
166 /* TODO: Vectored interrupt controller. */
167 switch (env
->exception_index
) {
169 new_mode
= ARM_CPU_MODE_UND
;
178 new_mode
= ARM_CPU_MODE_SVC
;
181 /* The PC already points to the next instructon. */
184 case EXCP_PREFETCH_ABORT
:
186 new_mode
= ARM_CPU_MODE_ABT
;
188 mask
= CPSR_A
| CPSR_I
;
191 case EXCP_DATA_ABORT
:
192 new_mode
= ARM_CPU_MODE_ABT
;
194 mask
= CPSR_A
| CPSR_I
;
198 new_mode
= ARM_CPU_MODE_IRQ
;
200 /* Disable IRQ and imprecise data aborts. */
201 mask
= CPSR_A
| CPSR_I
;
205 new_mode
= ARM_CPU_MODE_FIQ
;
207 /* Disable FIQ, IRQ and imprecise data aborts. */
208 mask
= CPSR_A
| CPSR_I
| CPSR_F
;
212 cpu_abort(env
, "Unhandled exception 0x%x\n", env
->exception_index
);
213 return; /* Never happens. Keep compiler happy. */
216 if (env
->cp15
.c1_sys
& (1 << 13)) {
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
;
226 env
->regs
[14] = env
->regs
[15] + offset
;
227 env
->regs
[15] = addr
;
228 env
->interrupt_request
|= CPU_INTERRUPT_EXITTB
;
231 /* Check section/page access permissions.
232 Returns the page protection flags, or zero if the access is not
234 static inline int check_ap(CPUState
*env
, int ap
, int domain
, int access_type
,
238 return PAGE_READ
| PAGE_WRITE
;
242 if (access_type
!= 1)
244 switch ((env
->cp15
.c1_sys
>> 8) & 3) {
246 return is_user
? 0 : PAGE_READ
;
253 return is_user
? 0 : PAGE_READ
| PAGE_WRITE
;
256 return (access_type
== 1) ? 0 : PAGE_READ
;
258 return PAGE_READ
| PAGE_WRITE
;
260 return PAGE_READ
| PAGE_WRITE
;
266 static int get_phys_addr(CPUState
*env
, uint32_t address
, int access_type
,
267 int is_user
, uint32_t *phys_ptr
, int *prot
)
277 /* Fast Context Switch Extension. */
278 if (address
< 0x02000000)
279 address
+= env
->cp15
.c13_fcse
;
281 if ((env
->cp15
.c1_sys
& 1) == 0) {
284 *prot
= PAGE_READ
| PAGE_WRITE
;
286 /* Pagetable walk. */
287 /* Lookup l1 descriptor. */
288 table
= (env
->cp15
.c2
& 0xffffc000) | ((address
>> 18) & 0x3ffc);
289 desc
= ldl_phys(table
);
291 domain
= (env
->cp15
.c3
>> ((desc
>> 4) & 0x1e)) & 3;
293 /* Secton translation fault. */
297 if (domain
== 0 || domain
== 2) {
299 code
= 9; /* Section domain fault. */
301 code
= 11; /* Page domain fault. */
306 phys_addr
= (desc
& 0xfff00000) | (address
& 0x000fffff);
307 ap
= (desc
>> 10) & 3;
310 /* Lookup l2 entry. */
311 table
= (desc
& 0xfffffc00) | ((address
>> 10) & 0x3fc);
312 desc
= ldl_phys(table
);
314 case 0: /* Page translation fault. */
317 case 1: /* 64k page. */
318 phys_addr
= (desc
& 0xffff0000) | (address
& 0xffff);
319 ap
= (desc
>> (4 + ((address
>> 13) & 6))) & 3;
321 case 2: /* 4k page. */
322 phys_addr
= (desc
& 0xfffff000) | (address
& 0xfff);
323 ap
= (desc
>> (4 + ((address
>> 13) & 6))) & 3;
325 case 3: /* 1k page. */
327 /* Page translation fault. */
331 phys_addr
= (desc
& 0xfffffc00) | (address
& 0x3ff);
332 ap
= (desc
>> 4) & 3;
335 /* Never happens, but compiler isn't smart enough to tell. */
340 *prot
= check_ap(env
, ap
, domain
, access_type
, is_user
);
342 /* Access permission fault. */
345 *phys_ptr
= phys_addr
;
349 return code
| (domain
<< 4);
352 int cpu_arm_handle_mmu_fault (CPUState
*env
, target_ulong address
,
353 int access_type
, int is_user
, int is_softmmu
)
359 ret
= get_phys_addr(env
, address
, access_type
, is_user
, &phys_addr
, &prot
);
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
,
368 if (access_type
== 2) {
369 env
->cp15
.c5_insn
= ret
;
370 env
->cp15
.c6_insn
= address
;
371 env
->exception_index
= EXCP_PREFETCH_ABORT
;
373 env
->cp15
.c5_data
= ret
;
374 env
->cp15
.c6_data
= address
;
375 env
->exception_index
= EXCP_DATA_ABORT
;
380 target_ulong
cpu_get_phys_page_debug(CPUState
*env
, target_ulong addr
)
386 ret
= get_phys_addr(env
, addr
, 0, 0, &phys_addr
, &prot
);
394 void helper_set_cp15(CPUState
*env
, uint32_t insn
, uint32_t val
)
398 op2
= (insn
>> 5) & 7;
399 switch ((insn
>> 16) & 0xf) {
400 case 0: /* ID codes. */
402 case 1: /* System configuration. */
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. */
411 env
->cp15
.c1_coproc
= val
;
412 /* ??? Is this safe when called from within a TB? */
418 case 2: /* MMU Page table control. */
421 case 3: /* MMU Domain access control. */
424 case 4: /* Reserved. */
426 case 5: /* MMU Fault status. */
429 env
->cp15
.c5_data
= val
;
432 env
->cp15
.c5_insn
= val
;
438 case 6: /* MMU Fault address. */
441 env
->cp15
.c6_data
= val
;
444 env
->cp15
.c6_insn
= val
;
450 case 7: /* Cache control. */
451 /* No cache, so nothing to do. */
453 case 8: /* MMU TLB control. */
455 case 0: /* Invalidate all. */
458 case 1: /* Invalidate single TLB entry. */
460 /* ??? This is wrong for large pages and sections. */
461 /* As an ugly hack to make linux work we always flush a 4K
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);
476 case 9: /* Cache lockdown. */
479 env
->cp15
.c9_data
= val
;
482 env
->cp15
.c9_insn
= val
;
488 case 10: /* MMU TLB lockdown. */
489 /* ??? TLB lockdown not implemented. */
491 case 11: /* TCM DMA control. */
492 case 12: /* Reserved. */
494 case 13: /* Process ID. */
497 env
->cp15
.c9_data
= val
;
500 env
->cp15
.c9_insn
= val
;
506 case 14: /* Reserved. */
508 case 15: /* Implementation specific. */
509 /* ??? Internal registers not implemented. */
514 /* ??? For debugging only. Should raise illegal instruction exception. */
515 cpu_abort(env
, "Unimplemented cp15 register read\n");
518 uint32_t helper_get_cp15(CPUState
*env
, uint32_t insn
)
522 op2
= (insn
>> 5) & 7;
523 switch ((insn
>> 16) & 0xf) {
524 case 0: /* ID codes. */
526 default: /* Device ID. */
527 return env
->cp15
.c0_cpuid
;
528 case 1: /* Cache Type. */
530 case 2: /* TCM status. */
533 case 1: /* System configuration. */
535 case 0: /* Control register. */
536 return env
->cp15
.c1_sys
;
537 case 1: /* Auxiliary control register. */
538 if (arm_feature(env
, ARM_FEATURE_AUXCR
))
541 case 2: /* Coprocessor access register. */
542 return env
->cp15
.c1_coproc
;
546 case 2: /* MMU Page table control. */
548 case 3: /* MMU Domain access control. */
550 case 4: /* Reserved. */
552 case 5: /* MMU Fault status. */
555 return env
->cp15
.c5_data
;
557 return env
->cp15
.c5_insn
;
561 case 6: /* MMU Fault address. */
564 return env
->cp15
.c6_data
;
566 /* Arm9 doesn't have an IFAR, but implementing it anyway shouldn't
568 return env
->cp15
.c6_insn
;
572 case 7: /* Cache control. */
573 /* ??? This is for test, clean and invaidate operations that set the
574 Z flag. We can't represent N = Z = 1, so it also clears clears
575 the N flag. Oh well. */
578 case 8: /* MMU TLB control. */
580 case 9: /* Cache lockdown. */
583 return env
->cp15
.c9_data
;
585 return env
->cp15
.c9_insn
;
589 case 10: /* MMU TLB lockdown. */
590 /* ??? TLB lockdown not implemented. */
592 case 11: /* TCM DMA control. */
593 case 12: /* Reserved. */
595 case 13: /* Process ID. */
598 return env
->cp15
.c13_fcse
;
600 return env
->cp15
.c13_context
;
604 case 14: /* Reserved. */
606 case 15: /* Implementation specific. */
607 /* ??? Internal registers not implemented. */
611 /* ??? For debugging only. Should raise illegal instruction exception. */
612 cpu_abort(env
, "Unimplemented cp15 register read\n");