2019-05-28 09:57:18 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2017-05-08 16:00:19 -07:00
/*
* Copyright 2017 , Anshuman Khandual , IBM Corp .
*
* Works on architectures which support 128 TB virtual
* address range and beyond .
*/
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <unistd.h>
# include <errno.h>
# include <sys/mman.h>
# include <sys/time.h>
/*
* Maximum address range mapped with a single mmap ( )
* call is little bit more than 16 GB . Hence 16 GB is
* chosen as the single chunk size for address space
* mapping .
*/
# define MAP_CHUNK_SIZE 17179869184UL /* 16GB */
/*
* Address space till 128 TB is mapped without any hint
* and is enabled by default . Address space beyond 128 TB
* till 512 TB is obtained by passing hint address as the
* first argument into mmap ( ) system call .
*
* The process heap address space is divided into two
* different areas one below 128 TB and one above 128 TB
* till it reaches 512 TB . One with size 128 TB and the
* other being 384 TB .
2017-05-18 14:52:58 +02:00
*
* On Arm64 the address space is 256 TB and no high mappings
* are supported so far .
2017-05-08 16:00:19 -07:00
*/
2017-05-18 14:52:58 +02:00
2017-05-08 16:00:19 -07:00
# define NR_CHUNKS_128TB 8192UL /* Number of 16GB chunks for 128TB */
2017-05-18 14:52:58 +02:00
# define NR_CHUNKS_256TB (NR_CHUNKS_128TB * 2UL)
# define NR_CHUNKS_384TB (NR_CHUNKS_128TB * 3UL)
2017-05-08 16:00:19 -07:00
# define ADDR_MARK_128TB (1UL << 47) /* First address beyond 128TB */
2017-05-18 14:52:58 +02:00
# define ADDR_MARK_256TB (1UL << 48) /* First address beyond 256TB */
# ifdef __aarch64__
# define HIGH_ADDR_MARK ADDR_MARK_256TB
# define HIGH_ADDR_SHIFT 49
# define NR_CHUNKS_LOW NR_CHUNKS_256TB
# define NR_CHUNKS_HIGH 0
# else
# define HIGH_ADDR_MARK ADDR_MARK_128TB
# define HIGH_ADDR_SHIFT 48
# define NR_CHUNKS_LOW NR_CHUNKS_128TB
# define NR_CHUNKS_HIGH NR_CHUNKS_384TB
# endif
2017-05-08 16:00:19 -07:00
static char * hind_addr ( void )
{
2017-05-18 14:52:58 +02:00
int bits = HIGH_ADDR_SHIFT + rand ( ) % ( 63 - HIGH_ADDR_SHIFT ) ;
2017-05-08 16:00:19 -07:00
return ( char * ) ( 1UL < < bits ) ;
}
static int validate_addr ( char * ptr , int high_addr )
{
unsigned long addr = ( unsigned long ) ptr ;
if ( high_addr ) {
2017-05-18 14:52:58 +02:00
if ( addr < HIGH_ADDR_MARK ) {
2017-05-08 16:00:19 -07:00
printf ( " Bad address %lx \n " , addr ) ;
return 1 ;
}
return 0 ;
}
2017-05-18 14:52:58 +02:00
if ( addr > HIGH_ADDR_MARK ) {
2017-05-08 16:00:19 -07:00
printf ( " Bad address %lx \n " , addr ) ;
return 1 ;
}
return 0 ;
}
static int validate_lower_address_hint ( void )
{
char * ptr ;
ptr = mmap ( ( void * ) ( 1UL < < 45 ) , MAP_CHUNK_SIZE , PROT_READ |
PROT_WRITE , MAP_PRIVATE | MAP_ANONYMOUS , - 1 , 0 ) ;
if ( ptr = = MAP_FAILED )
return 0 ;
return 1 ;
}
int main ( int argc , char * argv [ ] )
{
2017-05-18 14:52:58 +02:00
char * ptr [ NR_CHUNKS_LOW ] ;
char * hptr [ NR_CHUNKS_HIGH ] ;
2017-05-08 16:00:19 -07:00
char * hint ;
unsigned long i , lchunks , hchunks ;
2017-05-18 14:52:58 +02:00
for ( i = 0 ; i < NR_CHUNKS_LOW ; i + + ) {
2017-05-08 16:00:19 -07:00
ptr [ i ] = mmap ( NULL , MAP_CHUNK_SIZE , PROT_READ | PROT_WRITE ,
MAP_PRIVATE | MAP_ANONYMOUS , - 1 , 0 ) ;
if ( ptr [ i ] = = MAP_FAILED ) {
if ( validate_lower_address_hint ( ) )
return 1 ;
break ;
}
if ( validate_addr ( ptr [ i ] , 0 ) )
return 1 ;
}
lchunks = i ;
2017-05-18 14:52:58 +02:00
for ( i = 0 ; i < NR_CHUNKS_HIGH ; i + + ) {
2017-05-08 16:00:19 -07:00
hint = hind_addr ( ) ;
hptr [ i ] = mmap ( hint , MAP_CHUNK_SIZE , PROT_READ | PROT_WRITE ,
MAP_PRIVATE | MAP_ANONYMOUS , - 1 , 0 ) ;
if ( hptr [ i ] = = MAP_FAILED )
break ;
if ( validate_addr ( hptr [ i ] , 1 ) )
return 1 ;
}
hchunks = i ;
for ( i = 0 ; i < lchunks ; i + + )
munmap ( ptr [ i ] , MAP_CHUNK_SIZE ) ;
for ( i = 0 ; i < hchunks ; i + + )
munmap ( hptr [ i ] , MAP_CHUNK_SIZE ) ;
return 0 ;
}