2012-05-14 15:33:28 +09:00
/*
* TLB miss handler for SH with an MMU .
*
* Copyright ( C ) 1999 Niibe Yutaka
* Copyright ( C ) 2003 - 2012 Paul Mundt
*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
*/
# include <linux/kernel.h>
# include <linux/mm.h>
# include <linux/kprobes.h>
# include <linux/kdebug.h>
# include <asm/mmu_context.h>
# include <asm/thread_info.h>
/*
* Called with interrupts disabled .
*/
asmlinkage int __kprobes
handle_tlbmiss ( struct pt_regs * regs , unsigned long error_code ,
unsigned long address )
{
pgd_t * pgd ;
2020-06-04 16:46:56 -07:00
p4d_t * p4d ;
2012-05-14 15:33:28 +09:00
pud_t * pud ;
pmd_t * pmd ;
pte_t * pte ;
pte_t entry ;
/*
* We don ' t take page faults for P1 , P2 , and parts of P4 , these
* are always mapped , whether it be due to legacy behaviour in
* 29 - bit mode , or due to PMB configuration in 32 - bit mode .
*/
if ( address > = P3SEG & & address < P3_ADDR_MAX ) {
pgd = pgd_offset_k ( address ) ;
} else {
if ( unlikely ( address > = TASK_SIZE | | ! current - > mm ) )
return 1 ;
pgd = pgd_offset ( current - > mm , address ) ;
}
2020-06-04 16:46:56 -07:00
p4d = p4d_offset ( pgd , address ) ;
if ( p4d_none_or_clear_bad ( p4d ) )
return 1 ;
pud = pud_offset ( p4d , address ) ;
2012-05-14 15:33:28 +09:00
if ( pud_none_or_clear_bad ( pud ) )
return 1 ;
pmd = pmd_offset ( pud , address ) ;
if ( pmd_none_or_clear_bad ( pmd ) )
return 1 ;
pte = pte_offset_kernel ( pmd , address ) ;
entry = * pte ;
if ( unlikely ( pte_none ( entry ) | | pte_not_present ( entry ) ) )
return 1 ;
if ( unlikely ( error_code & & ! pte_write ( entry ) ) )
return 1 ;
if ( error_code )
entry = pte_mkdirty ( entry ) ;
entry = pte_mkyoung ( entry ) ;
set_pte ( pte , entry ) ;
# if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SMP)
/*
* SH - 4 does not set MMUCR . RC to the corresponding TLB entry in
* the case of an initial page write exception , so we need to
* flush it in order to avoid potential TLB entry duplication .
*/
if ( error_code = = FAULT_CODE_INITIAL )
local_flush_tlb_one ( get_asid ( ) , address & PAGE_MASK ) ;
# endif
set_thread_fault_code ( error_code ) ;
update_mmu_cache ( NULL , address , pte ) ;
return 0 ;
}