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