#include "cp15.h" #define CPUID_PXA255 0x69052D06UL //spepping A0 #define CPUID_PXA270 0x69054114UL //stepping C0 static Boolean cp15prvCoprocRegXferFunc(struct ArmCpu* cpu, void* userData, Boolean two, Boolean read, UInt8 op1, UInt8 Rx, UInt8 CRn, UInt8 CRm, UInt8 op2){ ArmCP15* cp15 = userData; UInt32 val = 0, tmp; if(!read) val = cpuGetRegExternal(cpu, Rx); if(op1 != 0 || two) goto fail; //CP15 only accessed with MCR/MRC with op1 == 0 switch(CRn){ case 0: //ID codes if(!read) goto fail; //cannot write to ID codes register if(CRm != 0) goto fail; //CRm must be zero for this read if(op2 == 0){ //main ID register val = CPUID_PXA255; goto success; } else if(op2 == 1){ //cahce type register - we lie here val = 0x0B16A16AUL; goto success; } break; case 1: //control register if(op2 == 0){ if(read){ val = cp15->control; } else{ tmp = val ^ cp15->control; //see what changed and mask off then chack for what we support changing of if(tmp & 0x84F0UL){ err_str("cp15: unknown bits changed 0x"); err_hex(cp15->control); err_str("->0x"); err_hex(val); err_str(", halting\r\n"); while(true); } if(tmp & 0x00002000UL){ // V bit cpuSetVectorAddr(cp15->cpu, (val & 0x00002000UL) ? 0xFFFF0000UL : 0x00000000UL); cp15->control ^= 0x00002000UL; } if(tmp & 0x00000200UL){ // R bit mmuSetR(cp15->mmu, (val & 0x00000200UL) != 0); cp15->control ^= 0x00000200UL; } if(tmp & 0x00000100UL){ // S bit mmuSetS(cp15->mmu, (val & 0x00000100UL) != 0); cp15->control ^= 0x00000100UL; } if(tmp & 0x00000001UL){ // M bit mmuSetTTP(cp15->mmu, (val & 0x00000001UL) ? cp15->ttb : MMU_DISABLED_TTP); mmuTlbFlush(cp15->mmu); cp15->control ^= 0x00000001UL; } } } else if(op2 == 1){ //PXA-specific thing if(read) val = cp15->ACP; else cp15->ACP = val; } else break; goto success; case 2: //translation tabler base if(read) val = cp15->ttb; else{ if(cp15->control & 0x00000001UL){ //mmu is on mmuSetTTP(cp15->mmu, val); mmuTlbFlush(cp15->mmu); } cp15->ttb = val; } goto success; case 3: //domain access control if(read) val = mmuGetDomainCfg(cp15->mmu); else mmuSetDomainCfg(cp15->mmu, val); goto success; case 5: //FSR if(read) val = cp15->FSR; else cp15->FSR = val; goto success; case 6: //FAR if(read) val = cp15->FAR; else cp15->FAR = val; goto success; case 7: //cache ops if((CRm == 5 || CRm == 7)&& op2 == 0) cpuIcacheInval(cp15->cpu); //invalidate entire {icache(5) or both i and dcache(7)} if((CRm == 5 || CRm == 7) && op2 == 1) cpuIcacheInvalAddr(cp15->cpu, val); //invalidate {icache(5) or both i and dcache(7)} line, given VA if((CRm == 5 || CRm == 7) && op2 == 2) cpuIcacheInval(cp15->cpu); //invalidate {icache(5) or both i and dcache(7)} line, given set/index. i dont know how to do this, so flush thee whole thing goto success; case 8: //TLB ops mmuTlbFlush(cp15->mmu); goto success; case 9: //cache lockdown if(CRm == 1 && op2 == 0){ err_str("Attempt to lock 0x"); err_hex(val); err_str("+32 in icache\r\n"); } else if(CRm == 2 && op2 == 0){ err_str("Dcache now "); err_str(val ? "in" : "out of"); err_str(" lock mode\r\n"); } goto success; case 10: //TLB lockdown goto success; case 13: //FCSE err_str("FCSE not supported\n"); break; case 15: if(op2 == 0 && CRm == 1){ //CPAR if(read) val = cpuGetCPAR(cp15->cpu); else cpuSetCPAR(cp15->cpu, val & 0x3FFF); goto success; } break; } fail: //TODO: cause invalid instruction trap in cpu return false; success: if(read) cpuSetReg(cpu, Rx, val); return true; } void cp15Init(ArmCP15* cp15, ArmCpu* cpu, ArmMmu* mmu){ ArmCoprocessor cp; cp.regXfer = cp15prvCoprocRegXferFunc; cp.dataProcessing = NULL; cp.memAccess = NULL; cp.twoRegF = NULL; cp.userData = cp15; __mem_zero(cp15, sizeof(ArmCP15)); cp15->cpu = cpu; cp15->mmu = mmu; cp15->control = 0x00004072UL; cpuCoprocessorRegister(cpu, 15, &cp); } void cp15Deinit(ArmCP15* cp15){ cpuCoprocessorUnregister(cp15->cpu, 15); } void cp15SetFaultStatus(ArmCP15* cp15, UInt32 addr, UInt8 faultStatus){ cp15->FAR = addr; cp15->FSR = faultStatus; }