162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Example of using hugepage memory in a user application using the mmap
462306a36Sopenharmony_ci * system call with MAP_HUGETLB flag.  Before running this program make
562306a36Sopenharmony_ci * sure the administrator has allocated enough default sized huge pages
662306a36Sopenharmony_ci * to cover the 256 MB allocation.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * For ia64 architecture, Linux kernel reserves Region number 4 for hugepages.
962306a36Sopenharmony_ci * That means the addresses starting with 0x800000... will need to be
1062306a36Sopenharmony_ci * specified.  Specifying a fixed address is not required on ppc64, i386
1162306a36Sopenharmony_ci * or x86_64.
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci#include <stdlib.h>
1462306a36Sopenharmony_ci#include <stdio.h>
1562306a36Sopenharmony_ci#include <unistd.h>
1662306a36Sopenharmony_ci#include <sys/mman.h>
1762306a36Sopenharmony_ci#include <fcntl.h>
1862306a36Sopenharmony_ci#include "vm_util.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define LENGTH (256UL*1024*1024)
2162306a36Sopenharmony_ci#define PROTECTION (PROT_READ | PROT_WRITE)
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci/* Only ia64 requires this */
2462306a36Sopenharmony_ci#ifdef __ia64__
2562306a36Sopenharmony_ci#define ADDR (void *)(0x8000000000000000UL)
2662306a36Sopenharmony_ci#define FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_FIXED)
2762306a36Sopenharmony_ci#else
2862306a36Sopenharmony_ci#define ADDR (void *)(0x0UL)
2962306a36Sopenharmony_ci#define FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB)
3062306a36Sopenharmony_ci#endif
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic void check_bytes(char *addr)
3362306a36Sopenharmony_ci{
3462306a36Sopenharmony_ci	printf("First hex is %x\n", *((unsigned int *)addr));
3562306a36Sopenharmony_ci}
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic void write_bytes(char *addr, size_t length)
3862306a36Sopenharmony_ci{
3962306a36Sopenharmony_ci	unsigned long i;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	for (i = 0; i < length; i++)
4262306a36Sopenharmony_ci		*(addr + i) = (char)i;
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic int read_bytes(char *addr, size_t length)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	unsigned long i;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	check_bytes(addr);
5062306a36Sopenharmony_ci	for (i = 0; i < length; i++)
5162306a36Sopenharmony_ci		if (*(addr + i) != (char)i) {
5262306a36Sopenharmony_ci			printf("Mismatch at %lu\n", i);
5362306a36Sopenharmony_ci			return 1;
5462306a36Sopenharmony_ci		}
5562306a36Sopenharmony_ci	return 0;
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ciint main(int argc, char **argv)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci	void *addr;
6162306a36Sopenharmony_ci	int ret;
6262306a36Sopenharmony_ci	size_t hugepage_size;
6362306a36Sopenharmony_ci	size_t length = LENGTH;
6462306a36Sopenharmony_ci	int flags = FLAGS;
6562306a36Sopenharmony_ci	int shift = 0;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	hugepage_size = default_huge_page_size();
6862306a36Sopenharmony_ci	/* munmap with fail if the length is not page aligned */
6962306a36Sopenharmony_ci	if (hugepage_size > length)
7062306a36Sopenharmony_ci		length = hugepage_size;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	if (argc > 1)
7362306a36Sopenharmony_ci		length = atol(argv[1]) << 20;
7462306a36Sopenharmony_ci	if (argc > 2) {
7562306a36Sopenharmony_ci		shift = atoi(argv[2]);
7662306a36Sopenharmony_ci		if (shift)
7762306a36Sopenharmony_ci			flags |= (shift & MAP_HUGE_MASK) << MAP_HUGE_SHIFT;
7862306a36Sopenharmony_ci	}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	if (shift)
8162306a36Sopenharmony_ci		printf("%u kB hugepages\n", 1 << (shift - 10));
8262306a36Sopenharmony_ci	else
8362306a36Sopenharmony_ci		printf("Default size hugepages\n");
8462306a36Sopenharmony_ci	printf("Mapping %lu Mbytes\n", (unsigned long)length >> 20);
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	addr = mmap(ADDR, length, PROTECTION, flags, -1, 0);
8762306a36Sopenharmony_ci	if (addr == MAP_FAILED) {
8862306a36Sopenharmony_ci		perror("mmap");
8962306a36Sopenharmony_ci		exit(1);
9062306a36Sopenharmony_ci	}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	printf("Returned address is %p\n", addr);
9362306a36Sopenharmony_ci	check_bytes(addr);
9462306a36Sopenharmony_ci	write_bytes(addr, length);
9562306a36Sopenharmony_ci	ret = read_bytes(addr, length);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	/* munmap() length of MAP_HUGETLB memory must be hugepage aligned */
9862306a36Sopenharmony_ci	if (munmap(addr, length)) {
9962306a36Sopenharmony_ci		perror("munmap");
10062306a36Sopenharmony_ci		exit(1);
10162306a36Sopenharmony_ci	}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	return ret;
10462306a36Sopenharmony_ci}
105