@ -501,7 +501,8 @@ static bool is_aligned(u64 addr, u64 size, u64 align)
return ! ( addr & ( align - 1 ) ) & & ! ( size & ( align - 1 ) ) ;
}
static u64 set_one_region ( u64 start , u64 size , u64 attrs , int level )
/* Use flag to indicate if attrs has more than d-cache attributes */
static u64 set_one_region ( u64 start , u64 size , u64 attrs , bool flag , int level )
{
int levelshift = level2shift ( level ) ;
u64 levelsize = 1ULL < < levelshift ;
@ -509,8 +510,13 @@ static u64 set_one_region(u64 start, u64 size, u64 attrs, int level)
/* Can we can just modify the current level block PTE? */
if ( is_aligned ( start , size , levelsize ) ) {
* pte & = ~ PMD_ATTRINDX_MASK ;
* pte | = attrs ;
if ( flag ) {
* pte & = ~ PMD_ATTRMASK ;
* pte | = attrs & PMD_ATTRMASK ;
} else {
* pte & = ~ PMD_ATTRINDX_MASK ;
* pte | = attrs & PMD_ATTRINDX_MASK ;
}
debug ( " Set attrs=%llx pte=%p level=%d \n " , attrs , pte , level ) ;
return levelsize ;
@ -560,7 +566,8 @@ void mmu_set_region_dcache_behaviour(phys_addr_t start, size_t size,
u64 r ;
for ( level = 1 ; level < 4 ; level + + ) {
r = set_one_region ( start , size , attrs , level ) ;
/* Set d-cache attributes only */
r = set_one_region ( start , size , attrs , false , level ) ;
if ( r ) {
/* PTE successfully replaced */
size - = r ;
@ -581,6 +588,63 @@ void mmu_set_region_dcache_behaviour(phys_addr_t start, size_t size,
flush_dcache_range ( real_start , real_start + real_size ) ;
}
/*
* Modify MMU table for a region with updated PXN / UXN / Memory type / valid bits .
* The procecess is break - before - make . The target region will be marked as
* invalid during the process of changing .
*/
void mmu_change_region_attr ( phys_addr_t addr , size_t siz , u64 attrs )
{
int level ;
u64 r , size , start ;
start = addr ;
size = siz ;
/*
* Loop through the address range until we find a page granule that fits
* our alignment constraints , then set it to " invalid " .
*/
while ( size > 0 ) {
for ( level = 1 ; level < 4 ; level + + ) {
/* Set PTE to fault */
r = set_one_region ( start , size , PTE_TYPE_FAULT , true ,
level ) ;
if ( r ) {
/* PTE successfully invalidated */
size - = r ;
start + = r ;
break ;
}
}
}
flush_dcache_range ( gd - > arch . tlb_addr ,
gd - > arch . tlb_addr + gd - > arch . tlb_size ) ;
__asm_invalidate_tlb_all ( ) ;
/*
* Loop through the address range until we find a page granule that fits
* our alignment constraints , then set it to the new cache attributes
*/
start = addr ;
size = siz ;
while ( size > 0 ) {
for ( level = 1 ; level < 4 ; level + + ) {
/* Set PTE to new attributes */
r = set_one_region ( start , size , attrs , true , level ) ;
if ( r ) {
/* PTE successfully updated */
size - = r ;
start + = r ;
break ;
}
}
}
flush_dcache_range ( gd - > arch . tlb_addr ,
gd - > arch . tlb_addr + gd - > arch . tlb_size ) ;
__asm_invalidate_tlb_all ( ) ;
}
# else /* CONFIG_SYS_DCACHE_OFF */
/*