2012-03-05 11:49:27 +00:00
/*
* Based on arch / arm / mm / mmap . c
*
* Copyright ( C ) 2012 ARM Ltd .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include <linux/elf.h>
# include <linux/fs.h>
# include <linux/mm.h>
# include <linux/mman.h>
# include <linux/export.h>
# include <linux/shm.h>
# include <linux/sched.h>
# include <linux/io.h>
# include <linux/personality.h>
# include <linux/random.h>
# include <asm/cputype.h>
/*
* Leave enough space between the mmap area and the stack to honour ulimit in
* the face of randomisation .
*/
# define MIN_GAP (SZ_128M + ((STACK_RND_MASK << PAGE_SHIFT) + 1))
# define MAX_GAP (STACK_TOP / 6*5)
static int mmap_is_legacy ( void )
{
if ( current - > personality & ADDR_COMPAT_LAYOUT )
return 1 ;
if ( rlimit ( RLIMIT_STACK ) = = RLIM_INFINITY )
return 1 ;
return sysctl_legacy_va_layout ;
}
static unsigned long mmap_rnd ( void )
{
2015-04-14 15:47:48 -07:00
unsigned long rnd ;
2012-03-05 11:49:27 +00:00
2015-04-14 15:47:48 -07:00
rnd = ( unsigned long ) get_random_int ( ) & STACK_RND_MASK ;
2012-03-05 11:49:27 +00:00
2014-11-17 23:02:19 +00:00
return rnd < < PAGE_SHIFT ;
2012-03-05 11:49:27 +00:00
}
2015-04-14 15:47:48 -07:00
static unsigned long mmap_base ( unsigned long rnd )
2012-03-05 11:49:27 +00:00
{
unsigned long gap = rlimit ( RLIMIT_STACK ) ;
if ( gap < MIN_GAP )
gap = MIN_GAP ;
else if ( gap > MAX_GAP )
gap = MAX_GAP ;
2015-04-14 15:47:48 -07:00
return PAGE_ALIGN ( STACK_TOP - gap - rnd ) ;
2012-03-05 11:49:27 +00:00
}
/*
* This function , called very early during the creation of a new process VM
* image , sets up which VM layout function to use :
*/
void arch_pick_mmap_layout ( struct mm_struct * mm )
{
2015-04-14 15:47:48 -07:00
unsigned long random_factor = 0UL ;
if ( current - > flags & PF_RANDOMIZE )
random_factor = mmap_rnd ( ) ;
2012-03-05 11:49:27 +00:00
/*
* Fall back to the standard layout if the personality bit is set , or
* if the expected stack growth is unlimited :
*/
if ( mmap_is_legacy ( ) ) {
2015-04-14 15:47:48 -07:00
mm - > mmap_base = TASK_UNMAPPED_BASE + random_factor ;
2012-03-05 11:49:27 +00:00
mm - > get_unmapped_area = arch_get_unmapped_area ;
} else {
2015-04-14 15:47:48 -07:00
mm - > mmap_base = mmap_base ( random_factor ) ;
2012-03-05 11:49:27 +00:00
mm - > get_unmapped_area = arch_get_unmapped_area_topdown ;
}
}
EXPORT_SYMBOL_GPL ( arch_pick_mmap_layout ) ;
/*
* You really shouldn ' t be using read ( ) or write ( ) on / dev / mem . This might go
* away in the future .
*/
2014-10-02 15:56:59 +01:00
int valid_phys_addr_range ( phys_addr_t addr , size_t size )
2012-03-05 11:49:27 +00:00
{
if ( addr < PHYS_OFFSET )
return 0 ;
if ( addr + size > __pa ( high_memory - 1 ) + 1 )
return 0 ;
return 1 ;
}
/*
* Do not allow / dev / mem mappings beyond the supported physical range .
*/
int valid_mmap_phys_addr_range ( unsigned long pfn , size_t size )
{
return ! ( ( ( pfn < < PAGE_SHIFT ) + size ) & ~ PHYS_MASK ) ;
}
# ifdef CONFIG_STRICT_DEVMEM
# include <linux/ioport.h>
/*
* devmem_is_allowed ( ) checks to see if / dev / mem access to a certain address
* is valid . The argument is a physical page number . We mimic x86 here by
* disallowing access to system RAM as well as device - exclusive MMIO regions .
* This effectively disable read ( ) / write ( ) on / dev / mem .
*/
int devmem_is_allowed ( unsigned long pfn )
{
if ( iomem_is_exclusive ( pfn < < PAGE_SHIFT ) )
return 0 ;
if ( ! page_is_ram ( pfn ) )
return 1 ;
return 0 ;
}
# endif