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 * On some old ppc64 kernel, when huge page is mapped at below touching 10f08c3bdfSopenharmony_ci * 32 bit boundary (4GB - hpage_size), and normal page is mmaped 11f08c3bdfSopenharmony_ci * at just above it, it triggers a bug caused by off-by-one error. 12f08c3bdfSopenharmony_ci * 13f08c3bdfSopenharmony_ci * WARNING: The offsets and addresses used within are specifically 14f08c3bdfSopenharmony_ci * calculated to trigger the bug as it existed. Don't mess with them 15f08c3bdfSopenharmony_ci * unless you *really* know what you're doing. 16f08c3bdfSopenharmony_ci */ 17f08c3bdfSopenharmony_ci 18f08c3bdfSopenharmony_ci#define _GNU_SOURCE 19f08c3bdfSopenharmony_ci#include <stdio.h> 20f08c3bdfSopenharmony_ci#include <sys/mount.h> 21f08c3bdfSopenharmony_ci#include <limits.h> 22f08c3bdfSopenharmony_ci#include <sys/param.h> 23f08c3bdfSopenharmony_ci#include <sys/types.h> 24f08c3bdfSopenharmony_ci 25f08c3bdfSopenharmony_ci#include "hugetlb.h" 26f08c3bdfSopenharmony_ci 27f08c3bdfSopenharmony_ci#define FOURGB (1ULL << 32) 28f08c3bdfSopenharmony_ci#define MNTPOINT "hugetlbfs/" 29f08c3bdfSopenharmony_cistatic int fd = -1; 30f08c3bdfSopenharmony_cistatic unsigned long long hpage_size; 31f08c3bdfSopenharmony_cistatic int page_size; 32f08c3bdfSopenharmony_ci 33f08c3bdfSopenharmony_cistatic void run_test(void) 34f08c3bdfSopenharmony_ci{ 35f08c3bdfSopenharmony_ci void *p, *q = NULL, *r = NULL; 36f08c3bdfSopenharmony_ci unsigned long long lowaddr, highaddr; 37f08c3bdfSopenharmony_ci unsigned long long below_start; 38f08c3bdfSopenharmony_ci unsigned long long above_end; 39f08c3bdfSopenharmony_ci 40f08c3bdfSopenharmony_ci /* 41f08c3bdfSopenharmony_ci * We use a low address right below 4GB so we can test for 42f08c3bdfSopenharmony_ci * off-by-one errors 43f08c3bdfSopenharmony_ci */ 44f08c3bdfSopenharmony_ci lowaddr = FOURGB - hpage_size; 45f08c3bdfSopenharmony_ci tst_res(TINFO, "Mapping hugepage at %llx...", lowaddr); 46f08c3bdfSopenharmony_ci p = mmap((void *)lowaddr, hpage_size, PROT_READ|PROT_WRITE, 47f08c3bdfSopenharmony_ci MAP_SHARED|MAP_FIXED, fd, 0); 48f08c3bdfSopenharmony_ci if (p == MAP_FAILED) { 49f08c3bdfSopenharmony_ci /* This is last low slice - 256M just before 4G */ 50f08c3bdfSopenharmony_ci below_start = FOURGB - 256ULL*1024*1024; 51f08c3bdfSopenharmony_ci above_end = FOURGB; 52f08c3bdfSopenharmony_ci 53f08c3bdfSopenharmony_ci if (range_is_mapped(below_start, above_end) == 1) { 54f08c3bdfSopenharmony_ci tst_res(TINFO|TERRNO, "region (4G-256M)-4G is not free & " 55f08c3bdfSopenharmony_ci "mmap() failed expected"); 56f08c3bdfSopenharmony_ci tst_res(TPASS, "Successful but inconclusive"); 57f08c3bdfSopenharmony_ci } else 58f08c3bdfSopenharmony_ci tst_res(TFAIL|TERRNO, "mmap() huge failed unexpected"); 59f08c3bdfSopenharmony_ci goto cleanup; 60f08c3bdfSopenharmony_ci } 61f08c3bdfSopenharmony_ci if (p != (void *)lowaddr) { 62f08c3bdfSopenharmony_ci tst_res(TFAIL, "Wrong address with MAP_FIXED huge"); 63f08c3bdfSopenharmony_ci goto cleanup; 64f08c3bdfSopenharmony_ci } 65f08c3bdfSopenharmony_ci memset(p, 0, hpage_size); 66f08c3bdfSopenharmony_ci 67f08c3bdfSopenharmony_ci /* Test for off by one errors */ 68f08c3bdfSopenharmony_ci highaddr = FOURGB; 69f08c3bdfSopenharmony_ci tst_res(TINFO, "Mapping normal page at %llx...", highaddr); 70f08c3bdfSopenharmony_ci q = mmap((void *)highaddr, page_size, PROT_READ|PROT_WRITE, 71f08c3bdfSopenharmony_ci MAP_SHARED|MAP_FIXED|MAP_ANONYMOUS, 0, 0); 72f08c3bdfSopenharmony_ci if (q == MAP_FAILED) { 73f08c3bdfSopenharmony_ci below_start = FOURGB; 74f08c3bdfSopenharmony_ci above_end = FOURGB + page_size; 75f08c3bdfSopenharmony_ci 76f08c3bdfSopenharmony_ci if (range_is_mapped(below_start, above_end) == 1) { 77f08c3bdfSopenharmony_ci tst_res(TINFO|TERRNO, "region 4G-(4G+page) is not free & " 78f08c3bdfSopenharmony_ci "mmap() failed expected"); 79f08c3bdfSopenharmony_ci tst_res(TPASS, "Successful but inconclusive"); 80f08c3bdfSopenharmony_ci } else 81f08c3bdfSopenharmony_ci tst_res(TFAIL|TERRNO, "mmap() normal 1 failed unexpected"); 82f08c3bdfSopenharmony_ci goto cleanup; 83f08c3bdfSopenharmony_ci } 84f08c3bdfSopenharmony_ci if (q != (void *)highaddr) { 85f08c3bdfSopenharmony_ci tst_res(TFAIL, "Wrong address with MAP_FIXED normal 1"); 86f08c3bdfSopenharmony_ci goto cleanup; 87f08c3bdfSopenharmony_ci } 88f08c3bdfSopenharmony_ci memset(q, 0, page_size); 89f08c3bdfSopenharmony_ci 90f08c3bdfSopenharmony_ci /* 91f08c3bdfSopenharmony_ci * Why this address? Well on ppc64, we're working with 256MB 92f08c3bdfSopenharmony_ci * segment numbers, hence >>28. In practice the shift 93f08c3bdfSopenharmony_ci * instructions only start wrapping around with shifts 128 or 94f08c3bdfSopenharmony_ci * greater. 95f08c3bdfSopenharmony_ci */ 96f08c3bdfSopenharmony_ci highaddr = ((lowaddr >> 28) + 128) << 28; 97f08c3bdfSopenharmony_ci tst_res(TINFO, "Mapping normal page at %llx...", highaddr); 98f08c3bdfSopenharmony_ci r = mmap((void *)highaddr, page_size, PROT_READ|PROT_WRITE, 99f08c3bdfSopenharmony_ci MAP_SHARED|MAP_FIXED|MAP_ANONYMOUS, 0, 0); 100f08c3bdfSopenharmony_ci if (r == MAP_FAILED) { 101f08c3bdfSopenharmony_ci below_start = highaddr; 102f08c3bdfSopenharmony_ci above_end = highaddr + page_size; 103f08c3bdfSopenharmony_ci 104f08c3bdfSopenharmony_ci if (range_is_mapped(below_start, above_end) == 1) { 105f08c3bdfSopenharmony_ci tst_res(TINFO|TERRNO, "region haddr-(haddr+page) not free & " 106f08c3bdfSopenharmony_ci "mmap() failed unexpected"); 107f08c3bdfSopenharmony_ci tst_res(TPASS, "Successful but inconclusive"); 108f08c3bdfSopenharmony_ci } 109f08c3bdfSopenharmony_ci tst_res(TFAIL|TERRNO, "mmap() normal 2 failed unexpected"); 110f08c3bdfSopenharmony_ci goto cleanup; 111f08c3bdfSopenharmony_ci } 112f08c3bdfSopenharmony_ci if (r != (void *)highaddr) { 113f08c3bdfSopenharmony_ci tst_res(TFAIL, "Wrong address with MAP_FIXED normal 2"); 114f08c3bdfSopenharmony_ci goto cleanup; 115f08c3bdfSopenharmony_ci } 116f08c3bdfSopenharmony_ci memset(r, 0, page_size); 117f08c3bdfSopenharmony_ci tst_res(TPASS, "Successful"); 118f08c3bdfSopenharmony_ci 119f08c3bdfSopenharmony_cicleanup: 120f08c3bdfSopenharmony_ci if (p && p != MAP_FAILED) 121f08c3bdfSopenharmony_ci SAFE_MUNMAP(p, hpage_size); 122f08c3bdfSopenharmony_ci if (q && q != MAP_FAILED) 123f08c3bdfSopenharmony_ci SAFE_MUNMAP(q, page_size); 124f08c3bdfSopenharmony_ci if (r && r != MAP_FAILED) 125f08c3bdfSopenharmony_ci SAFE_MUNMAP(r, page_size); 126f08c3bdfSopenharmony_ci} 127f08c3bdfSopenharmony_ci 128f08c3bdfSopenharmony_cistatic void setup(void) 129f08c3bdfSopenharmony_ci{ 130f08c3bdfSopenharmony_ci page_size = getpagesize(); 131f08c3bdfSopenharmony_ci hpage_size = SAFE_READ_MEMINFO("Hugepagesize:")*1024; 132f08c3bdfSopenharmony_ci 133f08c3bdfSopenharmony_ci if (sizeof(void *) <= 4) 134f08c3bdfSopenharmony_ci tst_brk(TCONF, "Machine must be >32 bit"); 135f08c3bdfSopenharmony_ci if (hpage_size > FOURGB) 136f08c3bdfSopenharmony_ci tst_brk(TCONF, "Huge page size is too large"); 137f08c3bdfSopenharmony_ci fd = tst_creat_unlinked(MNTPOINT, 0); 138f08c3bdfSopenharmony_ci} 139f08c3bdfSopenharmony_ci 140f08c3bdfSopenharmony_cistatic void cleanup(void) 141f08c3bdfSopenharmony_ci{ 142f08c3bdfSopenharmony_ci if (fd > 0) 143f08c3bdfSopenharmony_ci SAFE_CLOSE(fd); 144f08c3bdfSopenharmony_ci} 145f08c3bdfSopenharmony_ci 146f08c3bdfSopenharmony_cistatic struct tst_test test = { 147f08c3bdfSopenharmony_ci .tags = (struct tst_tag[]) { 148f08c3bdfSopenharmony_ci {"linux-git", "9a94c5793a7b"}, 149f08c3bdfSopenharmony_ci {} 150f08c3bdfSopenharmony_ci }, 151f08c3bdfSopenharmony_ci .needs_root = 1, 152f08c3bdfSopenharmony_ci .mntpoint = MNTPOINT, 153f08c3bdfSopenharmony_ci .needs_hugetlbfs = 1, 154f08c3bdfSopenharmony_ci .needs_tmpdir = 1, 155f08c3bdfSopenharmony_ci .setup = setup, 156f08c3bdfSopenharmony_ci .cleanup = cleanup, 157f08c3bdfSopenharmony_ci .test_all = run_test, 158f08c3bdfSopenharmony_ci .hugepages = {2, TST_NEEDS}, 159f08c3bdfSopenharmony_ci}; 160