1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: LGPL-2.1-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (C) 2005-2006 David Gibson & Adam Litke, IBM Corporation. 4f08c3bdfSopenharmony_ci * Author: David Gibson & Adam Litke 5f08c3bdfSopenharmony_ci */ 6f08c3bdfSopenharmony_ci 7f08c3bdfSopenharmony_ci/*\ 8f08c3bdfSopenharmony_ci * [Description] 9f08c3bdfSopenharmony_ci * 10f08c3bdfSopenharmony_ci * Certain kernels have a bug where brk() does not perform the same 11f08c3bdfSopenharmony_ci * checks that a MAP_FIXED mmap() will, allowing brk() to create a 12f08c3bdfSopenharmony_ci * normal page VMA in a hugepage only address region. This can lead 13f08c3bdfSopenharmony_ci * to oopses or other badness. 14f08c3bdfSopenharmony_ci */ 15f08c3bdfSopenharmony_ci 16f08c3bdfSopenharmony_ci#define _GNU_SOURCE 17f08c3bdfSopenharmony_ci#include <stdio.h> 18f08c3bdfSopenharmony_ci#include <sys/mount.h> 19f08c3bdfSopenharmony_ci#include <limits.h> 20f08c3bdfSopenharmony_ci#include <sys/param.h> 21f08c3bdfSopenharmony_ci#include <sys/types.h> 22f08c3bdfSopenharmony_ci 23f08c3bdfSopenharmony_ci#include "hugetlb.h" 24f08c3bdfSopenharmony_ci#include "tst_safe_stdio.h" 25f08c3bdfSopenharmony_ci 26f08c3bdfSopenharmony_ci#define MNTPOINT "hugetlbfs/" 27f08c3bdfSopenharmony_cistatic long hpage_size; 28f08c3bdfSopenharmony_cistatic int huge_fd = -1; 29f08c3bdfSopenharmony_ci 30f08c3bdfSopenharmony_ci#ifdef __powerpc64__ 31f08c3bdfSopenharmony_cistatic int arch_has_slice_support(void) 32f08c3bdfSopenharmony_ci{ 33f08c3bdfSopenharmony_ci char mmu_type[16]; 34f08c3bdfSopenharmony_ci 35f08c3bdfSopenharmony_ci SAFE_FILE_LINES_SCANF("/proc/cpuinfo", "MMU : %16s", mmu_type); 36f08c3bdfSopenharmony_ci return strcmp(mmu_type, "Hash") == 0; 37f08c3bdfSopenharmony_ci} 38f08c3bdfSopenharmony_ci 39f08c3bdfSopenharmony_cistatic void *next_chunk(void *addr) 40f08c3bdfSopenharmony_ci{ 41f08c3bdfSopenharmony_ci if (!arch_has_slice_support()) 42f08c3bdfSopenharmony_ci return PALIGN(addr, hpage_size); 43f08c3bdfSopenharmony_ci 44f08c3bdfSopenharmony_ci if ((unsigned long)addr < 0x100000000UL) 45f08c3bdfSopenharmony_ci /* 256M segments below 4G */ 46f08c3bdfSopenharmony_ci return PALIGN(addr, 0x10000000UL); 47f08c3bdfSopenharmony_ci /* 1TB segments above */ 48f08c3bdfSopenharmony_ci return PALIGN(addr, 0x10000000000UL); 49f08c3bdfSopenharmony_ci} 50f08c3bdfSopenharmony_ci#elif defined(__powerpc__) 51f08c3bdfSopenharmony_cistatic void *next_chunk(void *addr) 52f08c3bdfSopenharmony_ci{ 53f08c3bdfSopenharmony_ci if (tst_kernel_bits() == 32) 54f08c3bdfSopenharmony_ci return PALIGN(addr, hpage_size); 55f08c3bdfSopenharmony_ci else 56f08c3bdfSopenharmony_ci return PALIGN(addr, 0x10000000UL); 57f08c3bdfSopenharmony_ci} 58f08c3bdfSopenharmony_ci#elif defined(__ia64__) 59f08c3bdfSopenharmony_cistatic void *next_chunk(void *addr) 60f08c3bdfSopenharmony_ci{ 61f08c3bdfSopenharmony_ci return PALIGN(addr, 0x8000000000000000UL); 62f08c3bdfSopenharmony_ci} 63f08c3bdfSopenharmony_ci#else 64f08c3bdfSopenharmony_cistatic void *next_chunk(void *addr) 65f08c3bdfSopenharmony_ci{ 66f08c3bdfSopenharmony_ci return PALIGN(addr, hpage_size); 67f08c3bdfSopenharmony_ci} 68f08c3bdfSopenharmony_ci#endif 69f08c3bdfSopenharmony_ci 70f08c3bdfSopenharmony_cistatic void run_test(void) 71f08c3bdfSopenharmony_ci{ 72f08c3bdfSopenharmony_ci void *brk0, *hugemap_addr, *newbrk; 73f08c3bdfSopenharmony_ci char *p; 74f08c3bdfSopenharmony_ci int err; 75f08c3bdfSopenharmony_ci 76f08c3bdfSopenharmony_ci brk0 = sbrk(0); 77f08c3bdfSopenharmony_ci tst_res(TINFO, "Initial break at %p", brk0); 78f08c3bdfSopenharmony_ci 79f08c3bdfSopenharmony_ci hugemap_addr = next_chunk(brk0) + hpage_size; 80f08c3bdfSopenharmony_ci 81f08c3bdfSopenharmony_ci p = SAFE_MMAP(hugemap_addr, hpage_size, PROT_READ|PROT_WRITE, 82f08c3bdfSopenharmony_ci MAP_PRIVATE|MAP_FIXED, huge_fd, 0); 83f08c3bdfSopenharmony_ci if (p != hugemap_addr) { 84f08c3bdfSopenharmony_ci tst_res(TFAIL, "mmap() at unexpected address %p instead of %p\n", p, 85f08c3bdfSopenharmony_ci hugemap_addr); 86f08c3bdfSopenharmony_ci goto cleanup; 87f08c3bdfSopenharmony_ci } 88f08c3bdfSopenharmony_ci 89f08c3bdfSopenharmony_ci newbrk = next_chunk(brk0) + getpagesize(); 90f08c3bdfSopenharmony_ci err = brk((void *)newbrk); 91f08c3bdfSopenharmony_ci if (err == -1) { 92f08c3bdfSopenharmony_ci /* Failing the brk() is an acceptable kernel response */ 93f08c3bdfSopenharmony_ci tst_res(TPASS, "Failing the brk at %p is an acceptable response", 94f08c3bdfSopenharmony_ci newbrk); 95f08c3bdfSopenharmony_ci } else { 96f08c3bdfSopenharmony_ci /* Suceeding the brk() is acceptable if the new memory is 97f08c3bdfSopenharmony_ci * properly accesible and we don't have a kernel blow up when 98f08c3bdfSopenharmony_ci * we touch it. 99f08c3bdfSopenharmony_ci */ 100f08c3bdfSopenharmony_ci tst_res(TINFO, "New break at %p", newbrk); 101f08c3bdfSopenharmony_ci memset(brk0, 0, newbrk-brk0); 102f08c3bdfSopenharmony_ci tst_res(TPASS, "memory is accessible, hence successful brk() is " 103f08c3bdfSopenharmony_ci "an acceptable response"); 104f08c3bdfSopenharmony_ci } 105f08c3bdfSopenharmony_cicleanup: 106f08c3bdfSopenharmony_ci SAFE_MUNMAP(p, hpage_size); 107f08c3bdfSopenharmony_ci err = brk(brk0); 108f08c3bdfSopenharmony_ci if (err == -1) 109f08c3bdfSopenharmony_ci tst_brk(TBROK, "Failed to set break at the original position"); 110f08c3bdfSopenharmony_ci} 111f08c3bdfSopenharmony_ci 112f08c3bdfSopenharmony_cistatic void setup(void) 113f08c3bdfSopenharmony_ci{ 114f08c3bdfSopenharmony_ci hpage_size = SAFE_READ_MEMINFO(MEMINFO_HPAGE_SIZE)*1024; 115f08c3bdfSopenharmony_ci huge_fd = tst_creat_unlinked(MNTPOINT, 0); 116f08c3bdfSopenharmony_ci} 117f08c3bdfSopenharmony_ci 118f08c3bdfSopenharmony_cistatic void cleanup(void) 119f08c3bdfSopenharmony_ci{ 120f08c3bdfSopenharmony_ci SAFE_CLOSE(huge_fd); 121f08c3bdfSopenharmony_ci} 122f08c3bdfSopenharmony_ci 123f08c3bdfSopenharmony_cistatic struct tst_test test = { 124f08c3bdfSopenharmony_ci .needs_root = 1, 125f08c3bdfSopenharmony_ci .mntpoint = MNTPOINT, 126f08c3bdfSopenharmony_ci .needs_hugetlbfs = 1, 127f08c3bdfSopenharmony_ci .taint_check = TST_TAINT_D | TST_TAINT_W, 128f08c3bdfSopenharmony_ci .setup = setup, 129f08c3bdfSopenharmony_ci .cleanup = cleanup, 130f08c3bdfSopenharmony_ci .test_all = run_test, 131f08c3bdfSopenharmony_ci .hugepages = {1, TST_NEEDS}, 132f08c3bdfSopenharmony_ci}; 133