Annotation of qemu/target-arm/helper.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.