|
|
1.1 root 1: #include <stdio.h>
2: #include <stdlib.h>
3: #include <string.h>
4:
5: #include "cpu.h"
6: #include "exec-all.h"
7:
1.1.1.2 root 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:
1.1 root 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));
1.1.1.2 root 141: memcpy (env->regs + 8, env->usr_regs, 5 * sizeof(uint32_t));
1.1 root 142: } else if (mode == ARM_CPU_MODE_FIQ) {
143: memcpy (env->usr_regs, env->regs + 8, 5 * sizeof(uint32_t));
1.1.1.2 root 144: memcpy (env->regs + 8, env->fiq_regs, 5 * sizeof(uint32_t));
1.1 root 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:
1.1.1.2 root 185: case EXCP_BKPT:
1.1 root 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:
1.1.1.3 ! root 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;
1.1 root 503: break;
504: case 1:
1.1.1.3 ! root 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;
1.1 root 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. */
1.1.1.2 root 535: return env->cp15.c0_cpuid;
1.1 root 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. */
1.1.1.2 root 546: if (arm_feature(env, ARM_FEATURE_AUXCR))
547: return 1;
548: goto bad_reg;
1.1 root 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:
1.1.1.2 root 574: /* Arm9 doesn't have an IFAR, but implementing it anyway shouldn't
575: do any harm. */
1.1 root 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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.