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