forked from KolibriOS/kolibrios
187 lines
4.6 KiB
C
187 lines
4.6 KiB
C
|
#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;
|
||
|
}
|