1// SPDX-License-Identifier: LGPL-2.1-or-later 2/* 3 * Copyright (C) 2005-2006 David Gibson & Adam Litke, IBM Corporation. 4 * Author: David Gibson & Adam Litke 5 */ 6 7/*\ 8 * [Description] 9 * 10 * On some old ppc64 kernel, when hpage is mmaped on 32 bit boundary and 11 * normal page below it, it triggers the bug caused by off-by-one error. 12 * 13 * WARNING: The offsets and addresses used within are specifically 14 * calculated to trigger the bug as it existed. Don't mess with them 15 * unless you *really* know what you're doing. 16 */ 17 18#define _GNU_SOURCE 19#include <stdio.h> 20#include <sys/mount.h> 21#include <limits.h> 22#include <sys/param.h> 23#include <sys/types.h> 24 25#include "hugetlb.h" 26 27#define FOURGB (1ULL << 32) 28#define MNTPOINT "hugetlbfs/" 29static int fd = -1; 30static unsigned long hpage_size; 31static int page_size; 32 33static void run_test(void) 34{ 35 void *p, *q = NULL; 36 unsigned long long lowaddr; 37 unsigned long long below_start; 38 unsigned long long above_end; 39 40 p = mmap((void *)FOURGB, hpage_size, PROT_READ|PROT_WRITE, 41 MAP_SHARED | MAP_FIXED, fd, 0); 42 if (p == MAP_FAILED) { 43 /* slice 0 (high) spans from 4G-1T */ 44 below_start = FOURGB; 45 above_end = 1024ULL*1024*1024*1024; 46 47 if (range_is_mapped(below_start, above_end) == 1) { 48 tst_res(TINFO|TERRNO, "region 4G-IT is not free & " 49 "mmap() failed expected"); 50 tst_res(TPASS, "Successful but inconclusive"); 51 } else 52 tst_res(TFAIL|TERRNO, "mmap() huge failed unexpected"); 53 goto cleanup; 54 } 55 if (p != (void *)FOURGB) { 56 tst_res(TFAIL, "Wrong address with MAP_FIXED huge"); 57 goto cleanup; 58 } 59 60 tst_res(TINFO, "Mapped hugetlb at %p", p); 61 62 memset(p, 0, hpage_size); 63 64 /* Test just below 4GB to check for off-by-one errors */ 65 lowaddr = FOURGB - page_size; 66 q = mmap((void *)lowaddr, page_size, PROT_READ|PROT_WRITE, 67 MAP_SHARED|MAP_FIXED|MAP_ANONYMOUS, 0, 0); 68 if (q == MAP_FAILED) { 69 below_start = FOURGB - page_size; 70 above_end = FOURGB; 71 72 if (range_is_mapped(below_start, above_end) == 1) { 73 tst_res(TINFO|TERRNO, "region (4G-page)-4G is not free & " 74 "mmap() failed expected"); 75 tst_res(TPASS, "Successful but inconclusive"); 76 } else 77 tst_res(TFAIL|TERRNO, "mmap() normal failed unexpected"); 78 goto cleanup; 79 } 80 if (q != (void *)lowaddr) { 81 tst_res(TFAIL, "Wrong address with MAP_FIXED normal"); 82 goto cleanup; 83 } 84 85 memset(q, 0, page_size); 86 tst_res(TPASS, "Successful"); 87 88cleanup: 89 if (p && p != MAP_FAILED) 90 SAFE_MUNMAP(p, hpage_size); 91 if (q && q != MAP_FAILED) 92 SAFE_MUNMAP(q, page_size); 93} 94 95static void setup(void) 96{ 97 page_size = getpagesize(); 98 hpage_size = SAFE_READ_MEMINFO("Hugepagesize:")*1024; 99 100 if (sizeof(void *) <= 4) 101 tst_brk(TCONF, "Machine must be >32 bit"); 102 if (hpage_size > FOURGB) 103 tst_brk(TCONF, "Huge page size is too large"); 104 fd = tst_creat_unlinked(MNTPOINT, 0); 105} 106 107static void cleanup(void) 108{ 109 if (fd > 0) 110 SAFE_CLOSE(fd); 111} 112 113static struct tst_test test = { 114 .tags = (struct tst_tag[]) { 115 {"linux-git", "9a94c5793a7b"}, 116 {} 117 }, 118 .needs_root = 1, 119 .mntpoint = MNTPOINT, 120 .needs_hugetlbfs = 1, 121 .needs_tmpdir = 1, 122 .setup = setup, 123 .cleanup = cleanup, 124 .test_all = run_test, 125 .hugepages = {2, TST_NEEDS}, 126}; 127