Home | History | Annotate | Download | only in vm
      1 /*
      2  * Copyright 2017, Anshuman Khandual, IBM Corp.
      3  * Licensed under GPLv2.
      4  *
      5  * Works on architectures which support 128TB virtual
      6  * address range and beyond.
      7  */
      8 #include <stdio.h>
      9 #include <stdlib.h>
     10 #include <string.h>
     11 #include <unistd.h>
     12 #include <errno.h>
     13 #include <sys/mman.h>
     14 #include <sys/time.h>
     15 
     16 /*
     17  * Maximum address range mapped with a single mmap()
     18  * call is little bit more than 16GB. Hence 16GB is
     19  * chosen as the single chunk size for address space
     20  * mapping.
     21  */
     22 #define MAP_CHUNK_SIZE   17179869184UL /* 16GB */
     23 
     24 /*
     25  * Address space till 128TB is mapped without any hint
     26  * and is enabled by default. Address space beyond 128TB
     27  * till 512TB is obtained by passing hint address as the
     28  * first argument into mmap() system call.
     29  *
     30  * The process heap address space is divided into two
     31  * different areas one below 128TB and one above 128TB
     32  * till it reaches 512TB. One with size 128TB and the
     33  * other being 384TB.
     34  *
     35  * On Arm64 the address space is 256TB and no high mappings
     36  * are supported so far.
     37  */
     38 
     39 #define NR_CHUNKS_128TB   8192UL /* Number of 16GB chunks for 128TB */
     40 #define NR_CHUNKS_256TB   (NR_CHUNKS_128TB * 2UL)
     41 #define NR_CHUNKS_384TB   (NR_CHUNKS_128TB * 3UL)
     42 
     43 #define ADDR_MARK_128TB  (1UL << 47) /* First address beyond 128TB */
     44 #define ADDR_MARK_256TB  (1UL << 48) /* First address beyond 256TB */
     45 
     46 #ifdef __aarch64__
     47 #define HIGH_ADDR_MARK  ADDR_MARK_256TB
     48 #define HIGH_ADDR_SHIFT 49
     49 #define NR_CHUNKS_LOW   NR_CHUNKS_256TB
     50 #define NR_CHUNKS_HIGH  0
     51 #else
     52 #define HIGH_ADDR_MARK  ADDR_MARK_128TB
     53 #define HIGH_ADDR_SHIFT 48
     54 #define NR_CHUNKS_LOW   NR_CHUNKS_128TB
     55 #define NR_CHUNKS_HIGH  NR_CHUNKS_384TB
     56 #endif
     57 
     58 static char *hind_addr(void)
     59 {
     60 	int bits = HIGH_ADDR_SHIFT + rand() % (63 - HIGH_ADDR_SHIFT);
     61 
     62 	return (char *) (1UL << bits);
     63 }
     64 
     65 static int validate_addr(char *ptr, int high_addr)
     66 {
     67 	unsigned long addr = (unsigned long) ptr;
     68 
     69 	if (high_addr) {
     70 		if (addr < HIGH_ADDR_MARK) {
     71 			printf("Bad address %lx\n", addr);
     72 			return 1;
     73 		}
     74 		return 0;
     75 	}
     76 
     77 	if (addr > HIGH_ADDR_MARK) {
     78 		printf("Bad address %lx\n", addr);
     79 		return 1;
     80 	}
     81 	return 0;
     82 }
     83 
     84 static int validate_lower_address_hint(void)
     85 {
     86 	char *ptr;
     87 
     88 	ptr = mmap((void *) (1UL << 45), MAP_CHUNK_SIZE, PROT_READ |
     89 			PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
     90 
     91 	if (ptr == MAP_FAILED)
     92 		return 0;
     93 
     94 	return 1;
     95 }
     96 
     97 int main(int argc, char *argv[])
     98 {
     99 	char *ptr[NR_CHUNKS_LOW];
    100 	char *hptr[NR_CHUNKS_HIGH];
    101 	char *hint;
    102 	unsigned long i, lchunks, hchunks;
    103 
    104 	for (i = 0; i < NR_CHUNKS_LOW; i++) {
    105 		ptr[i] = mmap(NULL, MAP_CHUNK_SIZE, PROT_READ | PROT_WRITE,
    106 					MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    107 
    108 		if (ptr[i] == MAP_FAILED) {
    109 			if (validate_lower_address_hint())
    110 				return 1;
    111 			break;
    112 		}
    113 
    114 		if (validate_addr(ptr[i], 0))
    115 			return 1;
    116 	}
    117 	lchunks = i;
    118 
    119 	for (i = 0; i < NR_CHUNKS_HIGH; i++) {
    120 		hint = hind_addr();
    121 		hptr[i] = mmap(hint, MAP_CHUNK_SIZE, PROT_READ | PROT_WRITE,
    122 					MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    123 
    124 		if (hptr[i] == MAP_FAILED)
    125 			break;
    126 
    127 		if (validate_addr(hptr[i], 1))
    128 			return 1;
    129 	}
    130 	hchunks = i;
    131 
    132 	for (i = 0; i < lchunks; i++)
    133 		munmap(ptr[i], MAP_CHUNK_SIZE);
    134 
    135 	for (i = 0; i < hchunks; i++)
    136 		munmap(hptr[i], MAP_CHUNK_SIZE);
    137 
    138 	return 0;
    139 }
    140