added cp15 region access checks

This commit is contained in:
mightymax 2007-01-05 12:56:53 +00:00
parent 5180340738
commit 2f3bc5f92c
4 changed files with 361 additions and 4 deletions

View File

@ -28,6 +28,7 @@
#include "debug.h"
#include "NDSSystem.h"
#include "cflash.h"
#include "cp15.h"
#include "registers.h"
@ -402,7 +403,7 @@ u8 FASTCALL MMU_read8(u32 proc, u32 adr)
u16 FASTCALL MMU_read16(u32 proc, u32 adr)
{
{
if((proc == ARMCPU_ARM9) && ((adr & ~0x3FFF) == MMU.DTCMRegion))
{
/* Returns data from DTCM (ARM9 only) */
@ -2287,3 +2288,126 @@ void FASTCALL MMU_doDMA(u32 proc, u32 num)
break;
}
}
u8 FASTCALL MMU_read8_acl(u32 proc, u32 adr, u32 access)
{
if (proc == ARMCPU_ARM9) /* on arm9 we need to check the MPU regions */
{
if ((NDS_ARM9.CPSR.val & 0x1F) == 0x10)
{
/* is user mode access */
access &= ~1 ;
} else {
/* every other mode: sys */
access |= 1 ;
}
if (armcp15_isAccessAllowed((armcp15_t *)NDS_ARM9.coproc[15],adr,access)==FALSE)
{
execute = FALSE ;
}
}
return MMU_read8(proc,adr) ;
}
u16 FASTCALL MMU_read16_acl(u32 proc, u32 adr, u32 access)
{
if (proc == ARMCPU_ARM9) /* on arm9 we need to check the MPU regions */
{
if ((NDS_ARM9.CPSR.val & 0x1F) == 0x10)
{
/* is user mode access */
access &= ~1 ;
} else {
/* every other mode: sys */
access |= 1 ;
}
if (armcp15_isAccessAllowed((armcp15_t *)NDS_ARM9.coproc[15],adr,access)==FALSE)
{
execute = FALSE ;
}
}
return MMU_read16(proc,adr) ;
}
u32 FASTCALL MMU_read32_acl(u32 proc, u32 adr, u32 access)
{
if (proc == ARMCPU_ARM9) /* on arm9 we need to check the MPU regions */
{
if ((NDS_ARM9.CPSR.val & 0x1F) == 0x10)
{
/* is user mode access */
access &= ~1 ;
} else {
/* every other mode: sys */
access |= 1 ;
}
if (armcp15_isAccessAllowed((armcp15_t *)NDS_ARM9.coproc[15],adr,access)==FALSE)
{
execute = FALSE ;
}
}
return MMU_read32(proc,adr) ;
}
void FASTCALL MMU_write8_acl(u32 proc, u32 adr, u8 val)
{
if (proc == ARMCPU_ARM9) /* on arm9 we need to check the MPU regions */
{
u32 access = CP15_ACCESS_WRITE ;
if ((NDS_ARM9.CPSR.val & 0x1F) == 0x10)
{
/* is user mode access */
access &= ~1 ;
} else {
/* every other mode: sys */
access |= 1 ;
}
if (armcp15_isAccessAllowed((armcp15_t *)NDS_ARM9.coproc[15],adr,access)==FALSE)
{
execute = FALSE ;
}
}
MMU_write8(proc,adr,val) ;
}
void FASTCALL MMU_write16_acl(u32 proc, u32 adr, u16 val)
{
if (proc == ARMCPU_ARM9) /* on arm9 we need to check the MPU regions */
{
u32 access = CP15_ACCESS_WRITE ;
if ((NDS_ARM9.CPSR.val & 0x1F) == 0x10)
{
/* is user mode access */
access &= ~1 ;
} else {
/* every other mode: sys */
access |= 1 ;
}
if (armcp15_isAccessAllowed((armcp15_t *)NDS_ARM9.coproc[15],adr,access)==FALSE)
{
execute = FALSE ;
}
}
MMU_write16(proc,adr,val) ;
}
void FASTCALL MMU_write32_acl(u32 proc, u32 adr, u32 val)
{
if (proc == ARMCPU_ARM9) /* on arm9 we need to check the MPU regions */
{
u32 access = CP15_ACCESS_WRITE ;
if ((NDS_ARM9.CPSR.val & 0x1F) == 0x10)
{
/* is user mode access */
access &= ~1 ;
} else {
/* every other mode: sys */
access |= 1 ;
}
if (armcp15_isAccessAllowed((armcp15_t *)NDS_ARM9.coproc[15],adr,access)==FALSE)
{
execute = FALSE ;
}
}
MMU_write32(proc,adr,val) ;
}

View File

@ -106,20 +106,34 @@ void MMU_setRom(u8 * rom, u32 mask);
void MMU_unsetRom();
#define MMU_readByte MMU_read8
#define MMU_readHWord MMU_read16
#define MMU_readHWord MMU_read16
#define MMU_readWord MMU_read32
#define MMU_readByteACL MMU_read8_acl
#define MMU_readHWordACL MMU_read16_acl
#define MMU_readWordACL MMU_read32_acl
u8 FASTCALL MMU_read8(u32 proc, u32 adr);
u16 FASTCALL MMU_read16(u32 proc, u32 adr);
u32 FASTCALL MMU_read32(u32 proc, u32 adr);
u8 FASTCALL MMU_read8_acl(u32 proc, u32 adr, u32 access);
u16 FASTCALL MMU_read16_acl(u32 proc, u32 adr, u32 access);
u32 FASTCALL MMU_read32_acl(u32 proc, u32 adr, u32 access);
#define MMU_writeByte MMU_write8
#define MMU_writeHWord MMU_write16
#define MMU_writeWord MMU_write32
#define MMU_writeByteACL MMU_write8_acl
#define MMU_writeHWordACL MMU_write16_acl
#define MMU_writeWordACL MMU_write32_acl
void FASTCALL MMU_write8(u32 proc, u32 adr, u8 val);
void FASTCALL MMU_write16(u32 proc, u32 adr, u16 val);
void FASTCALL MMU_write32(u32 proc, u32 adr, u32 val);
void FASTCALL MMU_write8_acl(u32 proc, u32 adr, u8 val);
void FASTCALL MMU_write16_acl(u32 proc, u32 adr, u16 val);
void FASTCALL MMU_write32_acl(u32 proc, u32 adr, u32 val);
void FASTCALL MMU_doDMA(u32 proc, u32 num);

View File

@ -55,10 +55,195 @@ armcp15_t *armcp15_new(armcpu_t * c)
armcp15->ITCMRegion = 0x0C;
armcp15->DTCMRegion = 0x0080000A;
armcp15->processID = 0;
/* preset calculated regionmasks */
int i ;
for (i=0;i<8;i++) {
armcp15->regionWriteMask_USR[i] = 0 ;
armcp15->regionWriteMask_SYS[i] = 0 ;
armcp15->regionReadMask_USR[i] = 0 ;
armcp15->regionReadMask_SYS[i] = 0 ;
armcp15->regionExecuteMask_USR[i] = 0 ;
armcp15->regionExecuteMask_SYS[i] = 0 ;
armcp15->regionWriteSet_USR[i] = 0 ;
armcp15->regionWriteSet_SYS[i] = 0 ;
armcp15->regionReadSet_USR[i] = 0 ;
armcp15->regionReadSet_SYS[i] = 0 ;
armcp15->regionExecuteSet_USR[i] = 0 ;
armcp15->regionExecuteSet_SYS[i] = 0 ;
} ;
return armcp15;
}
#define ACCESSTYPE(val,n) (((val) > (4*n)) & 0x0F)
#define SIZEIDENTIFIER(val) ((((val) >> 1) & 0x1F))
#define SIZEBINARY(val) (1 << (SIZEIDENTIFIER(val)+1))
#define MASKFROMREG(val) (~((SIZEBINARY(val)-1) | 0x3F))
#define SETFROMREG(val) ((val) & MASKFROMREG(val))
/* sets the precalculated regions to mask,set for the affected accesstypes */
void armcp15_setSingleRegionAccess(armcp15_t *armcp15,unsigned long dAccess,unsigned long iAccess,unsigned char num, unsigned long mask,unsigned long set) {
switch (ACCESSTYPE(dAccess,num)) {
case 4: /* UNP */
case 7: /* UNP */
case 8: /* UNP */
case 9: /* UNP */
case 10: /* UNP */
case 11: /* UNP */
case 12: /* UNP */
case 13: /* UNP */
case 14: /* UNP */
case 15: /* UNP */
case 0: /* no access at all */
armcp15->regionWriteMask_USR[num] = 0 ;
armcp15->regionWriteSet_USR[num] = 0xFFFFFFFF ;
armcp15->regionReadMask_USR[num] = 0 ;
armcp15->regionReadSet_USR[num] = 0xFFFFFFFF ;
armcp15->regionWriteMask_SYS[num] = 0 ;
armcp15->regionWriteSet_SYS[num] = 0xFFFFFFFF ;
armcp15->regionReadMask_SYS[num] = 0 ;
armcp15->regionReadSet_SYS[num] = 0xFFFFFFFF ;
break ;
case 1: /* no access at USR, all to sys */
armcp15->regionWriteMask_USR[num] = 0 ;
armcp15->regionWriteSet_USR[num] = 0xFFFFFFFF ;
armcp15->regionReadMask_USR[num] = 0 ;
armcp15->regionReadSet_USR[num] = 0xFFFFFFFF ;
armcp15->regionWriteMask_SYS[num] = mask ;
armcp15->regionWriteSet_SYS[num] = set ;
armcp15->regionReadMask_SYS[num] = mask ;
armcp15->regionReadSet_SYS[num] = set ;
break ;
case 2: /* read at USR, all to sys */
armcp15->regionWriteMask_USR[num] = 0 ;
armcp15->regionWriteSet_USR[num] = 0xFFFFFFFF ;
armcp15->regionReadMask_USR[num] = mask ;
armcp15->regionReadSet_USR[num] = set ;
armcp15->regionWriteMask_SYS[num] = mask ;
armcp15->regionWriteSet_SYS[num] = set ;
armcp15->regionReadMask_SYS[num] = mask ;
armcp15->regionReadSet_SYS[num] = set ;
break ;
case 3: /* all to USR, all to sys */
armcp15->regionWriteMask_USR[num] = mask ;
armcp15->regionWriteSet_USR[num] = set ;
armcp15->regionReadMask_USR[num] = mask ;
armcp15->regionReadSet_USR[num] = set ;
armcp15->regionWriteMask_SYS[num] = mask ;
armcp15->regionWriteSet_SYS[num] = set ;
armcp15->regionReadMask_SYS[num] = mask ;
armcp15->regionReadSet_SYS[num] = set ;
break ;
case 5: /* no access at USR, read to sys */
armcp15->regionWriteMask_USR[num] = 0 ;
armcp15->regionWriteSet_USR[num] = 0xFFFFFFFF ;
armcp15->regionReadMask_USR[num] = 0 ;
armcp15->regionReadSet_USR[num] = 0xFFFFFFFF ;
armcp15->regionWriteMask_SYS[num] = 0 ;
armcp15->regionWriteSet_SYS[num] = 0xFFFFFFFF ;
armcp15->regionReadMask_SYS[num] = mask ;
armcp15->regionReadSet_SYS[num] = set ;
break ;
case 6: /* read at USR, read to sys */
armcp15->regionWriteMask_USR[num] = 0 ;
armcp15->regionWriteSet_USR[num] = 0xFFFFFFFF ;
armcp15->regionReadMask_USR[num] = mask ;
armcp15->regionReadSet_USR[num] = set ;
armcp15->regionWriteMask_SYS[num] = 0 ;
armcp15->regionWriteSet_SYS[num] = 0xFFFFFFFF ;
armcp15->regionReadMask_SYS[num] = mask ;
armcp15->regionReadSet_SYS[num] = set ;
break ;
}
switch (ACCESSTYPE(iAccess,num)) {
case 4: /* UNP */
case 7: /* UNP */
case 8: /* UNP */
case 9: /* UNP */
case 10: /* UNP */
case 11: /* UNP */
case 12: /* UNP */
case 13: /* UNP */
case 14: /* UNP */
case 15: /* UNP */
case 0: /* no access at all */
armcp15->regionExecuteMask_USR[num] = 0 ;
armcp15->regionExecuteSet_USR[num] = 0xFFFFFFFF ;
armcp15->regionExecuteMask_SYS[num] = 0 ;
armcp15->regionExecuteSet_SYS[num] = 0xFFFFFFFF ;
break ;
case 1:
armcp15->regionExecuteMask_USR[num] = 0 ;
armcp15->regionExecuteSet_USR[num] = 0xFFFFFFFF ;
armcp15->regionExecuteMask_SYS[num] = mask ;
armcp15->regionExecuteSet_SYS[num] = set ;
break ;
case 2:
case 3:
case 6:
armcp15->regionExecuteMask_USR[num] = mask ;
armcp15->regionExecuteSet_USR[num] = set ;
armcp15->regionExecuteMask_SYS[num] = mask ;
armcp15->regionExecuteSet_SYS[num] = set ;
break ;
}
} ;
/* precalculate region masks/sets from cp15 register */
void armcp15_maskPrecalc(armcp15_t *armcp15)
{
#define precalc(num) { \
u32 mask = 0, set = 0xFFFFFFFF ; /* (x & 0) == 0xFF..FF is allways false (disabled) */ \
if (BIT_N(armcp15->protectBaseSize##num,0)) /* if region is enabled */ \
{ /* reason for this define: naming includes var */ \
mask = MASKFROMREG(armcp15->protectBaseSize##num) ; \
set = SETFROMREG(armcp15->protectBaseSize##num) ; \
if (SIZEIDENTIFIER(armcp15->protectBaseSize##num)==0x1F) \
{ /* for the 4GB region, u32 suffers wraparound */ \
mask = 0 ; set = 0 ; /* (x & 0) == 0 is allways true (enabled) */ \
} \
} \
armcp15_setSingleRegionAccess(armcp15,armcp15->DaccessPerm,armcp15->IaccessPerm,num,mask,set) ; \
}
precalc(0) ;
precalc(1) ;
precalc(2) ;
precalc(3) ;
precalc(4) ;
precalc(5) ;
precalc(6) ;
precalc(7) ;
}
BOOL armcp15_isAccessAllowed(armcp15_t *armcp15,u32 address,u32 access)
{
if (!(armcp15->ctrl & 1)) return TRUE ; /* protection checking is not enabled */
int i ;
for (i=0;i<8;i++) {
switch (access) {
case CP15_ACCESS_WRITEUSR:
if ((address & armcp15->regionWriteMask_USR[i]) == armcp15->regionWriteSet_USR[i]) return TRUE ;
break ;
case CP15_ACCESS_WRITESYS:
if ((address & armcp15->regionWriteMask_SYS[i]) == armcp15->regionWriteSet_SYS[i]) return TRUE ;
break ;
case CP15_ACCESS_READUSR:
if ((address & armcp15->regionReadMask_USR[i]) == armcp15->regionReadSet_USR[i]) return TRUE ;
break ;
case CP15_ACCESS_READSYS:
if ((address & armcp15->regionReadMask_SYS[i]) == armcp15->regionReadSet_SYS[i]) return TRUE ;
break ;
case CP15_ACCESS_EXECUSR:
if ((address & armcp15->regionExecuteMask_USR[i]) == armcp15->regionExecuteSet_USR[i]) return TRUE ;
break ;
case CP15_ACCESS_EXECSYS:
if ((address & armcp15->regionExecuteMask_SYS[i]) == armcp15->regionExecuteSet_SYS[i]) return TRUE ;
break ;
}
}
/* when protections are enabled, but no region allows access, deny access */
return FALSE ;
}
BOOL armcp15_dataProcess(armcp15_t *armcp15, u8 CRd, u8 CRn, u8 CRm, u8 opcode1, u8 opcode2)
{
@ -136,7 +321,7 @@ BOOL armcp15_moveCP2ARM(armcp15_t *armcp15, u32 * R, u8 CRn, u8 CRm, u8 opcode1,
{
case 2 :
*R = armcp15->DaccessPerm;
return TRUE;
return TRUE;
case 3 :
*R = armcp15->IaccessPerm;
return TRUE;
@ -293,7 +478,7 @@ BOOL armcp15_moveARM2CP(armcp15_t *armcp15, u32 val, u8 CRn, u8 CRm, u8 opcode1,
{
case 2 :
armcp15->DaccessPerm = val;
return TRUE;
return TRUE;
case 3 :
armcp15->IaccessPerm = val;
return TRUE;
@ -309,27 +494,35 @@ BOOL armcp15_moveARM2CP(armcp15_t *armcp15, u32 val, u8 CRn, u8 CRm, u8 opcode1,
{
case 0 :
armcp15->protectBaseSize0 = val;
armcp15_maskPrecalc(armcp15) ;
return TRUE;
case 1 :
armcp15->protectBaseSize1 = val;
armcp15_maskPrecalc(armcp15) ;
return TRUE;
case 2 :
armcp15->protectBaseSize2 = val;
armcp15_maskPrecalc(armcp15) ;
return TRUE;
case 3 :
armcp15->protectBaseSize3 = val;
armcp15_maskPrecalc(armcp15) ;
return TRUE;
case 4 :
armcp15->protectBaseSize4 = val;
armcp15_maskPrecalc(armcp15) ;
return TRUE;
case 5 :
armcp15->protectBaseSize5 = val;
armcp15_maskPrecalc(armcp15) ;
return TRUE;
case 6 :
armcp15->protectBaseSize6 = val;
armcp15_maskPrecalc(armcp15) ;
return TRUE;
case 7 :
armcp15->protectBaseSize7 = val;
armcp15_maskPrecalc(armcp15) ;
return TRUE;
default :
return FALSE;

View File

@ -53,6 +53,20 @@ typedef struct
u32 RAM_TAG;
u32 testState;
u32 cacheDbg;
/* calculated bitmasks for the regions to decide rights uppon */
/* calculation is done in the MCR instead of on mem access for performance */
u32 regionWriteMask_USR[8] ;
u32 regionWriteMask_SYS[8] ;
u32 regionReadMask_USR[8] ;
u32 regionReadMask_SYS[8] ;
u32 regionExecuteMask_USR[8] ;
u32 regionExecuteMask_SYS[8] ;
u32 regionWriteSet_USR[8] ;
u32 regionWriteSet_SYS[8] ;
u32 regionReadSet_USR[8] ;
u32 regionReadSet_SYS[8] ;
u32 regionExecuteSet_USR[8] ;
u32 regionExecuteSet_SYS[8] ;
armcpu_t * cpu;
@ -64,5 +78,17 @@ BOOL armcp15_load(armcp15_t *armcp15, u8 CRd, u8 adr);
BOOL armcp15_store(armcp15_t *armcp15, u8 CRd, u8 adr);
BOOL armcp15_moveCP2ARM(armcp15_t *armcp15, u32 * R, u8 CRn, u8 CRm, u8 opcode1, u8 opcode2);
BOOL armcp15_moveARM2CP(armcp15_t *armcp15, u32 val, u8 CRn, u8 CRm, u8 opcode1, u8 opcode2);
BOOL armcp15_isAccessAllowed(armcp15_t *armcp15,u32 address,u32 access) ;
#define CP15_ACCESS_WRITE 0
#define CP15_ACCESS_READ 2
#define CP15_ACCESS_EXECUTE 4
#define CP15_ACCESS_WRITEUSR CP15_ACCESS_WRITE
#define CP15_ACCESS_WRITESYS 1
#define CP15_ACCESS_READUSR CP15_ACCESS_READ
#define CP15_ACCESS_READSYS 3
#define CP15_ACCESS_EXECUSR CP15_ACCESS_EXECUTE
#define CP15_ACCESS_EXECSYS 5
#endif /* __CP15_H__*/