2006-06-22 18:05:36 +04:00
/*
* linux / arch / arm / mm / nommu . c
*
* ARM uCLinux supporting functions .
*/
# include <linux/module.h>
2006-06-24 13:46:23 +04:00
# include <linux/mm.h>
# include <linux/pagemap.h>
2008-09-06 15:10:45 +04:00
# include <linux/io.h>
2010-07-09 19:27:52 +04:00
# include <linux/memblock.h>
2013-02-28 21:46:36 +04:00
# include <linux/kernel.h>
2006-06-22 18:05:36 +04:00
2006-06-24 13:46:23 +04:00
# include <asm/cacheflush.h>
2017-02-01 15:46:36 +03:00
# include <asm/cp15.h>
2008-12-01 14:53:07 +03:00
# include <asm/sections.h>
2006-06-22 18:05:36 +04:00
# include <asm/page.h>
2009-07-24 15:35:03 +04:00
# include <asm/setup.h>
2012-04-12 20:16:01 +04:00
# include <asm/traps.h>
2006-11-30 16:53:54 +03:00
# include <asm/mach/arch.h>
2013-02-28 21:46:36 +04:00
# include <asm/cputype.h>
# include <asm/mpu.h>
2013-11-14 14:58:30 +04:00
# include <asm/procinfo.h>
2006-06-22 18:05:36 +04:00
2006-09-27 18:27:33 +04:00
# include "mm.h"
2017-02-01 15:46:36 +03:00
unsigned long vectors_base ;
2013-02-28 21:46:36 +04:00
# ifdef CONFIG_ARM_MPU
struct mpu_rgn_info mpu_rgn_info ;
2017-10-16 14:52:35 +03:00
# endif
2013-02-28 21:46:36 +04:00
2017-02-01 15:46:36 +03:00
# ifdef CONFIG_CPU_CP15
# ifdef CONFIG_CPU_HIGH_VECTOR
2017-12-27 12:38:55 +03:00
unsigned long setup_vectors_base ( void )
2017-02-01 15:46:36 +03:00
{
unsigned long reg = get_cr ( ) ;
set_cr ( reg | CR_V ) ;
return 0xffff0000 ;
}
# else /* CONFIG_CPU_HIGH_VECTOR */
/* Write exception base address to VBAR */
static inline void set_vbar ( unsigned long val )
{
asm ( " mcr p15, 0, %0, c12, c0, 0 " : : " r " ( val ) : " cc " ) ;
}
/*
* Security extensions , bits [ 7 : 4 ] , permitted values ,
* 0 b0000 - not implemented , 0 b0001 / 0 b0010 - implemented
*/
static inline bool security_extensions_enabled ( void )
{
2017-03-23 15:49:32 +03:00
/* Check CPUID Identification Scheme before ID_PFR1 read */
if ( ( read_cpuid_id ( ) & 0x000f0000 ) = = 0x000f0000 )
return ! ! cpuid_feature_extract ( CPUID_EXT_PFR1 , 4 ) ;
return 0 ;
2017-02-01 15:46:36 +03:00
}
2017-12-27 12:38:55 +03:00
unsigned long setup_vectors_base ( void )
2017-02-01 15:46:36 +03:00
{
unsigned long base = 0 , reg = get_cr ( ) ;
set_cr ( reg & ~ CR_V ) ;
if ( security_extensions_enabled ( ) ) {
if ( IS_ENABLED ( CONFIG_REMAP_VECTORS_TO_RAM ) )
base = CONFIG_DRAM_BASE ;
set_vbar ( base ) ;
} else if ( IS_ENABLED ( CONFIG_REMAP_VECTORS_TO_RAM ) ) {
if ( CONFIG_DRAM_BASE ! = 0 )
pr_err ( " Security extensions not enabled, vectors cannot be remapped to RAM, vectors base will be 0x00000000 \n " ) ;
}
return base ;
}
# endif /* CONFIG_CPU_HIGH_VECTOR */
# endif /* CONFIG_CPU_CP15 */
2010-07-09 19:27:52 +04:00
void __init arm_mm_memblock_reserve ( void )
2006-09-27 18:27:33 +04:00
{
2010-05-21 21:06:41 +04:00
# ifndef CONFIG_CPU_V7M
2017-02-01 15:46:36 +03:00
vectors_base = IS_ENABLED ( CONFIG_CPU_CP15 ) ? setup_vectors_base ( ) : 0 ;
2006-09-27 18:27:33 +04:00
/*
* Register the exception vector page .
* some architectures which the DRAM is the exception vector to trap ,
* alloc_page breaks with error , although it is not NULL , but " 0. "
*/
2017-02-01 15:46:36 +03:00
memblock_reserve ( vectors_base , 2 * PAGE_SIZE ) ;
2010-05-21 21:06:41 +04:00
# else /* ifndef CONFIG_CPU_V7M */
/*
* There is no dedicated vector page on V7 - M . So nothing needs to be
* reserved here .
*/
# endif
2017-10-01 04:06:27 +03:00
/*
* In any case , always ensure address 0 is never used as many things
* get very confused if 0 is returned as a legitimate address .
*/
memblock_reserve ( 0 , 1 ) ;
2006-09-27 18:27:33 +04:00
}
2018-04-03 12:36:37 +03:00
static void __init adjust_lowmem_bounds_mpu ( void )
{
unsigned long pmsa = read_cpuid_ext ( CPUID_EXT_MMFR0 ) & MMFR0_PMSA ;
switch ( pmsa ) {
case MMFR0_PMSAv7 :
pmsav7_adjust_lowmem_bounds ( ) ;
break ;
2018-04-03 12:39:23 +03:00
case MMFR0_PMSAv8 :
pmsav8_adjust_lowmem_bounds ( ) ;
break ;
2018-04-03 12:36:37 +03:00
default :
break ;
}
}
static void __init mpu_setup ( void )
{
unsigned long pmsa = read_cpuid_ext ( CPUID_EXT_MMFR0 ) & MMFR0_PMSA ;
switch ( pmsa ) {
case MMFR0_PMSAv7 :
pmsav7_setup ( ) ;
break ;
2018-04-03 12:39:23 +03:00
case MMFR0_PMSAv8 :
pmsav8_setup ( ) ;
break ;
2018-04-03 12:36:37 +03:00
default :
break ;
}
}
2017-01-14 00:51:08 +03:00
void __init adjust_lowmem_bounds ( void )
2011-07-05 22:58:29 +04:00
{
2013-02-28 21:51:05 +04:00
phys_addr_t end ;
2017-01-14 00:51:08 +03:00
adjust_lowmem_bounds_mpu ( ) ;
2014-04-14 01:54:58 +04:00
end = memblock_end_of_DRAM ( ) ;
2011-09-19 06:40:00 +04:00
high_memory = __va ( end - 1 ) + 1 ;
2014-06-27 13:17:27 +04:00
memblock_set_current_limit ( end ) ;
2011-07-05 22:58:29 +04:00
}
2006-09-27 18:27:33 +04:00
/*
* paging_init ( ) sets up the page tables , initialises the zone memory
* maps , and sets up the zero page , bad page and bad page tables .
*/
2013-07-26 17:55:59 +04:00
void __init paging_init ( const struct machine_desc * mdesc )
2006-09-27 18:27:33 +04:00
{
2017-02-01 15:46:36 +03:00
early_trap_init ( ( void * ) vectors_base ) ;
2013-02-28 21:51:05 +04:00
mpu_setup ( ) ;
2010-05-22 22:47:18 +04:00
bootmem_init ( ) ;
2006-09-27 18:27:33 +04:00
}
2006-09-27 18:43:47 +04:00
/*
* We don ' t need to do anything here for nommu machines .
*/
2011-11-01 14:15:27 +04:00
void setup_mm_for_reboot ( void )
2006-09-27 18:43:47 +04:00
{
}
2006-06-24 13:46:23 +04:00
void flush_dcache_page ( struct page * page )
{
2009-11-26 15:56:21 +03:00
__cpuc_flush_dcache_area ( page_address ( page ) , PAGE_SIZE ) ;
2006-06-24 13:46:23 +04:00
}
2006-06-27 23:55:43 +04:00
EXPORT_SYMBOL ( flush_dcache_page ) ;
2006-06-24 13:46:23 +04:00
2013-06-23 01:01:25 +04:00
void flush_kernel_dcache_page ( struct page * page )
{
__cpuc_flush_dcache_area ( page_address ( page ) , PAGE_SIZE ) ;
}
EXPORT_SYMBOL ( flush_kernel_dcache_page ) ;
2010-05-06 18:15:28 +04:00
void copy_to_user_page ( struct vm_area_struct * vma , struct page * page ,
unsigned long uaddr , void * dst , const void * src ,
unsigned long len )
{
memcpy ( dst , src , len ) ;
if ( vma - > vm_flags & VM_EXEC )
__cpuc_coherent_user_range ( uaddr , uaddr + len ) ;
}
2007-05-05 23:59:27 +04:00
void __iomem * __arm_ioremap_pfn ( unsigned long pfn , unsigned long offset ,
size_t size , unsigned int mtype )
2006-06-22 18:05:36 +04:00
{
if ( pfn > = ( 0x100000000ULL > > PAGE_SHIFT ) )
return NULL ;
return ( void __iomem * ) ( offset + ( pfn < < PAGE_SHIFT ) ) ;
}
2007-05-05 23:59:27 +04:00
EXPORT_SYMBOL ( __arm_ioremap_pfn ) ;
2006-06-22 18:05:36 +04:00
2015-07-01 12:06:32 +03:00
void __iomem * __arm_ioremap_caller ( phys_addr_t phys_addr , size_t size ,
unsigned int mtype , void * caller )
2009-12-18 14:10:03 +03:00
{
2015-07-01 12:06:32 +03:00
return ( void __iomem * ) phys_addr ;
2009-12-18 14:10:03 +03:00
}
2015-07-01 12:06:32 +03:00
void __iomem * ( * arch_ioremap_caller ) ( phys_addr_t , size_t , unsigned int , void * ) ;
void __iomem * ioremap ( resource_size_t res_cookie , size_t size )
2006-06-22 18:05:36 +04:00
{
2015-07-01 12:06:32 +03:00
return __arm_ioremap_caller ( res_cookie , size , MT_DEVICE ,
__builtin_return_address ( 0 ) ) ;
2006-06-22 18:05:36 +04:00
}
2015-07-01 12:06:32 +03:00
EXPORT_SYMBOL ( ioremap ) ;
2006-06-22 18:05:36 +04:00
2015-07-01 12:06:32 +03:00
void __iomem * ioremap_cache ( resource_size_t res_cookie , size_t size )
2016-03-04 12:05:39 +03:00
__alias ( ioremap_cached ) ;
void __iomem * ioremap_cached ( resource_size_t res_cookie , size_t size )
2015-07-01 12:06:32 +03:00
{
return __arm_ioremap_caller ( res_cookie , size , MT_DEVICE_CACHED ,
__builtin_return_address ( 0 ) ) ;
}
EXPORT_SYMBOL ( ioremap_cache ) ;
2016-03-04 12:05:39 +03:00
EXPORT_SYMBOL ( ioremap_cached ) ;
2012-03-11 07:24:04 +04:00
2015-07-01 12:06:32 +03:00
void __iomem * ioremap_wc ( resource_size_t res_cookie , size_t size )
{
return __arm_ioremap_caller ( res_cookie , size , MT_DEVICE_WC ,
__builtin_return_address ( 0 ) ) ;
}
EXPORT_SYMBOL ( ioremap_wc ) ;
2017-04-19 19:48:53 +03:00
# ifdef CONFIG_PCI
# include <asm/mach/map.h>
void __iomem * pci_remap_cfgspace ( resource_size_t res_cookie , size_t size )
{
return arch_ioremap_caller ( res_cookie , size , MT_UNCACHED ,
__builtin_return_address ( 0 ) ) ;
}
EXPORT_SYMBOL_GPL ( pci_remap_cfgspace ) ;
# endif
2016-02-22 17:02:08 +03:00
void * arch_memremap_wb ( phys_addr_t phys_addr , size_t size )
{
return ( void * ) phys_addr ;
}
2015-07-01 12:06:32 +03:00
void __iounmap ( volatile void __iomem * addr )
2009-12-18 14:10:03 +03:00
{
}
2015-07-01 12:06:32 +03:00
EXPORT_SYMBOL ( __iounmap ) ;
2009-12-18 14:10:03 +03:00
2012-03-11 07:24:04 +04:00
void ( * arch_iounmap ) ( volatile void __iomem * ) ;
2015-07-01 12:06:32 +03:00
void iounmap ( volatile void __iomem * addr )
2006-06-22 18:05:36 +04:00
{
}
2015-07-01 12:06:32 +03:00
EXPORT_SYMBOL ( iounmap ) ;