Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/tools/testing/selftests/mm/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 8 kB image not shown  

Quelle  va_high_addr_switch.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 *
 * Authors: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
 * Authors: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
 */


#include <stdio.h>
#include <sys/mman.h>
#include <string.h>

#include "vm_util.h"
#include "../kselftest.h"

/*
 * The hint addr value is used to allocate addresses
 * beyond the high address switch boundary.
 */


#define ADDR_MARK_128TB (1UL << 47)
#define ADDR_MARK_256TB (1UL << 48)

#define HIGH_ADDR_128TB (1UL << 48)
#define HIGH_ADDR_256TB (1UL << 49)

struct testcase {
 void *addr;
 unsigned long size;
 unsigned long flags;
 const char *msg;
 unsigned int low_addr_required:1;
 unsigned int keep_mapped:1;
};

static struct testcase *testcases;
static struct testcase *hugetlb_testcases;
static int sz_testcases, sz_hugetlb_testcases;
static unsigned long switch_hint;

/* Initialize testcases inside a function to compute parameters at runtime */
void testcases_init(void)
{
 unsigned long pagesize = getpagesize();
 unsigned long hugepagesize = default_huge_page_size();
 unsigned long low_addr = (1UL << 30);
 unsigned long addr_switch_hint = ADDR_MARK_128TB;
 unsigned long high_addr = HIGH_ADDR_128TB;

#ifdef __aarch64__

 /* Post LPA2, the lower userspace VA on a 16K pagesize is 47 bits. */
 if (pagesize != (16UL << 10)) {
  addr_switch_hint = ADDR_MARK_256TB;
  high_addr = HIGH_ADDR_256TB;
 }
#endif

 struct testcase t[] = {
  {
   /*
 * If stack is moved, we could possibly allocate
 * this at the requested address.
 */

   .addr = ((void *)(addr_switch_hint - pagesize)),
   .size = pagesize,
   .flags = MAP_PRIVATE | MAP_ANONYMOUS,
   .msg = "mmap(addr_switch_hint - pagesize, pagesize)",
   .low_addr_required = 1,
  },
  {
   /*
 * Unless MAP_FIXED is specified, allocation based on hint
 * addr is never at requested address or above it, which is
 * beyond high address switch boundary in this case. Instead,
 * a suitable allocation is found in lower address space.
 */

   .addr = ((void *)(addr_switch_hint - pagesize)),
   .size = 2 * pagesize,
   .flags = MAP_PRIVATE | MAP_ANONYMOUS,
   .msg = "mmap(addr_switch_hint - pagesize, (2 * pagesize))",
   .low_addr_required = 1,
  },
  {
   /*
 * Exact mapping at high address switch boundary, should
 * be obtained even without MAP_FIXED as area is free.
 */

   .addr = ((void *)(addr_switch_hint)),
   .size = pagesize,
   .flags = MAP_PRIVATE | MAP_ANONYMOUS,
   .msg = "mmap(addr_switch_hint, pagesize)",
   .keep_mapped = 1,
  },
  {
   .addr = (void *)(addr_switch_hint),
   .size = 2 * pagesize,
   .flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
   .msg = "mmap(addr_switch_hint, 2 * pagesize, MAP_FIXED)",
  },
  {
   .addr = NULL,
   .size = 2 * pagesize,
   .flags = MAP_PRIVATE | MAP_ANONYMOUS,
   .msg = "mmap(NULL)",
   .low_addr_required = 1,
  },
  {
   .addr = (void *)low_addr,
   .size = 2 * pagesize,
   .flags = MAP_PRIVATE | MAP_ANONYMOUS,
   .msg = "mmap(low_addr)",
   .low_addr_required = 1,
  },
  {
   .addr = (void *)high_addr,
   .size = 2 * pagesize,
   .flags = MAP_PRIVATE | MAP_ANONYMOUS,
   .msg = "mmap(high_addr)",
   .keep_mapped = 1,
  },
  {
   .addr = (void *)high_addr,
   .size = 2 * pagesize,
   .flags = MAP_PRIVATE | MAP_ANONYMOUS,
   .msg = "mmap(high_addr) again",
   .keep_mapped = 1,
  },
  {
   .addr = (void *)high_addr,
   .size = 2 * pagesize,
   .flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
   .msg = "mmap(high_addr, MAP_FIXED)",
  },
  {
   .addr = (void *) -1,
   .size = 2 * pagesize,
   .flags = MAP_PRIVATE | MAP_ANONYMOUS,
   .msg = "mmap(-1)",
   .keep_mapped = 1,
  },
  {
   .addr = (void *) -1,
   .size = 2 * pagesize,
   .flags = MAP_PRIVATE | MAP_ANONYMOUS,
   .msg = "mmap(-1) again",
  },
  {
   .addr = ((void *)(addr_switch_hint - pagesize)),
   .size = pagesize,
   .flags = MAP_PRIVATE | MAP_ANONYMOUS,
   .msg = "mmap(addr_switch_hint - pagesize, pagesize)",
   .low_addr_required = 1,
  },
  {
   .addr = (void *)(addr_switch_hint - pagesize),
   .size = 2 * pagesize,
   .flags = MAP_PRIVATE | MAP_ANONYMOUS,
   .msg = "mmap(addr_switch_hint - pagesize, 2 * pagesize)",
   .low_addr_required = 1,
   .keep_mapped = 1,
  },
  {
   .addr = (void *)(addr_switch_hint - pagesize / 2),
   .size = 2 * pagesize,
   .flags = MAP_PRIVATE | MAP_ANONYMOUS,
   .msg = "mmap(addr_switch_hint - pagesize/2 , 2 * pagesize)",
   .low_addr_required = 1,
   .keep_mapped = 1,
  },
  {
   .addr = ((void *)(addr_switch_hint)),
   .size = pagesize,
   .flags = MAP_PRIVATE | MAP_ANONYMOUS,
   .msg = "mmap(addr_switch_hint, pagesize)",
  },
  {
   .addr = (void *)(addr_switch_hint),
   .size = 2 * pagesize,
   .flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
   .msg = "mmap(addr_switch_hint, 2 * pagesize, MAP_FIXED)",
  },
 };

 struct testcase ht[] = {
  {
   .addr = NULL,
   .size = hugepagesize,
   .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
   .msg = "mmap(NULL, MAP_HUGETLB)",
   .low_addr_required = 1,
  },
  {
   .addr = (void *)low_addr,
   .size = hugepagesize,
   .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
   .msg = "mmap(low_addr, MAP_HUGETLB)",
   .low_addr_required = 1,
  },
  {
   .addr = (void *)high_addr,
   .size = hugepagesize,
   .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
   .msg = "mmap(high_addr, MAP_HUGETLB)",
   .keep_mapped = 1,
  },
  {
   .addr = (void *)high_addr,
   .size = hugepagesize,
   .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
   .msg = "mmap(high_addr, MAP_HUGETLB) again",
   .keep_mapped = 1,
  },
  {
   .addr = (void *)high_addr,
   .size = hugepagesize,
   .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
   .msg = "mmap(high_addr, MAP_FIXED | MAP_HUGETLB)",
  },
  {
   .addr = (void *) -1,
   .size = hugepagesize,
   .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
   .msg = "mmap(-1, MAP_HUGETLB)",
   .keep_mapped = 1,
  },
  {
   .addr = (void *) -1,
   .size = hugepagesize,
   .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
   .msg = "mmap(-1, MAP_HUGETLB) again",
  },
  {
   .addr = (void *)(addr_switch_hint - hugepagesize),
   .size = 2 * hugepagesize,
   .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
   .msg = "mmap(addr_switch_hint - hugepagesize, 2*hugepagesize, MAP_HUGETLB)",
   .low_addr_required = 1,
   .keep_mapped = 1,
  },
  {
   .addr = (void *)(addr_switch_hint),
   .size = 2 * hugepagesize,
   .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
   .msg = "mmap(addr_switch_hint , 2*hugepagesize, MAP_FIXED | MAP_HUGETLB)",
  },
 };

 testcases = malloc(sizeof(t));
 hugetlb_testcases = malloc(sizeof(ht));

 /* Copy into global arrays */
 memcpy(testcases, t, sizeof(t));
 memcpy(hugetlb_testcases, ht, sizeof(ht));

 sz_testcases = ARRAY_SIZE(t);
 sz_hugetlb_testcases = ARRAY_SIZE(ht);
 switch_hint = addr_switch_hint;
}

static int run_test(struct testcase *test, int count)
{
 void *p;
 int i, ret = KSFT_PASS;

 for (i = 0; i < count; i++) {
  struct testcase *t = test + i;

  p = mmap(t->addr, t->size, PROT_READ | PROT_WRITE, t->flags, -1, 0);

  printf("%s: %p - ", t->msg, p);

  if (p == MAP_FAILED) {
   printf("FAILED\n");
   ret = KSFT_FAIL;
   continue;
  }

  if (t->low_addr_required && p >= (void *)(switch_hint)) {
   printf("FAILED\n");
   ret = KSFT_FAIL;
  } else {
   /*
 * Do a dereference of the address returned so that we catch
 * bugs in page fault handling
 */

   memset(p, 0, t->size);
   printf("OK\n");
  }
  if (!t->keep_mapped)
   munmap(p, t->size);
 }

 return ret;
}

#ifdef __aarch64__
/* Check if userspace VA > 48 bits */
static int high_address_present(void)
{
 void *ptr = mmap((void *)(1UL << 50), 1, PROT_READ | PROT_WRITE,
    MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
 if (ptr == MAP_FAILED)
  return 0;

 munmap(ptr, 1);
 return 1;
}
#endif

static int supported_arch(void)
{
#if defined(__powerpc64__)
 return 1;
#elif defined(__x86_64__)
 return 1;
#elif defined(__aarch64__)
 return high_address_present();
#else
 return 0;
#endif
}

int main(int argc, char **argv)
{
 int ret;

 if (!supported_arch())
  return KSFT_SKIP;

 testcases_init();

 ret = run_test(testcases, sz_testcases);
 if (argc == 2 && !strcmp(argv[1], "--run-hugetlb"))
  ret = run_test(hugetlb_testcases, sz_hugetlb_testcases);
 return ret;
}

Messung V0.5
C=96 H=95 G=95

¤ Dauer der Verarbeitung: 0.4 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.