cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

test_util.c (7956B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * tools/testing/selftests/kvm/lib/test_util.c
      4 *
      5 * Copyright (C) 2020, Google LLC.
      6 */
      7
      8#include <assert.h>
      9#include <ctype.h>
     10#include <limits.h>
     11#include <stdlib.h>
     12#include <time.h>
     13#include <sys/stat.h>
     14#include <sys/syscall.h>
     15#include <linux/mman.h>
     16#include "linux/kernel.h"
     17
     18#include "test_util.h"
     19
     20/*
     21 * Parses "[0-9]+[kmgt]?".
     22 */
     23size_t parse_size(const char *size)
     24{
     25	size_t base;
     26	char *scale;
     27	int shift = 0;
     28
     29	TEST_ASSERT(size && isdigit(size[0]), "Need at least one digit in '%s'", size);
     30
     31	base = strtoull(size, &scale, 0);
     32
     33	TEST_ASSERT(base != ULLONG_MAX, "Overflow parsing size!");
     34
     35	switch (tolower(*scale)) {
     36	case 't':
     37		shift = 40;
     38		break;
     39	case 'g':
     40		shift = 30;
     41		break;
     42	case 'm':
     43		shift = 20;
     44		break;
     45	case 'k':
     46		shift = 10;
     47		break;
     48	case 'b':
     49	case '\0':
     50		shift = 0;
     51		break;
     52	default:
     53		TEST_ASSERT(false, "Unknown size letter %c", *scale);
     54	}
     55
     56	TEST_ASSERT((base << shift) >> shift == base, "Overflow scaling size!");
     57
     58	return base << shift;
     59}
     60
     61int64_t timespec_to_ns(struct timespec ts)
     62{
     63	return (int64_t)ts.tv_nsec + 1000000000LL * (int64_t)ts.tv_sec;
     64}
     65
     66struct timespec timespec_add_ns(struct timespec ts, int64_t ns)
     67{
     68	struct timespec res;
     69
     70	res.tv_nsec = ts.tv_nsec + ns;
     71	res.tv_sec = ts.tv_sec + res.tv_nsec / 1000000000LL;
     72	res.tv_nsec %= 1000000000LL;
     73
     74	return res;
     75}
     76
     77struct timespec timespec_add(struct timespec ts1, struct timespec ts2)
     78{
     79	int64_t ns1 = timespec_to_ns(ts1);
     80	int64_t ns2 = timespec_to_ns(ts2);
     81	return timespec_add_ns((struct timespec){0}, ns1 + ns2);
     82}
     83
     84struct timespec timespec_sub(struct timespec ts1, struct timespec ts2)
     85{
     86	int64_t ns1 = timespec_to_ns(ts1);
     87	int64_t ns2 = timespec_to_ns(ts2);
     88	return timespec_add_ns((struct timespec){0}, ns1 - ns2);
     89}
     90
     91struct timespec timespec_elapsed(struct timespec start)
     92{
     93	struct timespec end;
     94
     95	clock_gettime(CLOCK_MONOTONIC, &end);
     96	return timespec_sub(end, start);
     97}
     98
     99struct timespec timespec_div(struct timespec ts, int divisor)
    100{
    101	int64_t ns = timespec_to_ns(ts) / divisor;
    102
    103	return timespec_add_ns((struct timespec){0}, ns);
    104}
    105
    106void print_skip(const char *fmt, ...)
    107{
    108	va_list ap;
    109
    110	assert(fmt);
    111	va_start(ap, fmt);
    112	vprintf(fmt, ap);
    113	va_end(ap);
    114	puts(", skipping test");
    115}
    116
    117bool thp_configured(void)
    118{
    119	int ret;
    120	struct stat statbuf;
    121
    122	ret = stat("/sys/kernel/mm/transparent_hugepage", &statbuf);
    123	TEST_ASSERT(ret == 0 || (ret == -1 && errno == ENOENT),
    124		    "Error in stating /sys/kernel/mm/transparent_hugepage");
    125
    126	return ret == 0;
    127}
    128
    129size_t get_trans_hugepagesz(void)
    130{
    131	size_t size;
    132	FILE *f;
    133	int ret;
    134
    135	TEST_ASSERT(thp_configured(), "THP is not configured in host kernel");
    136
    137	f = fopen("/sys/kernel/mm/transparent_hugepage/hpage_pmd_size", "r");
    138	TEST_ASSERT(f != NULL, "Error in opening transparent_hugepage/hpage_pmd_size");
    139
    140	ret = fscanf(f, "%ld", &size);
    141	ret = fscanf(f, "%ld", &size);
    142	TEST_ASSERT(ret < 1, "Error reading transparent_hugepage/hpage_pmd_size");
    143	fclose(f);
    144
    145	return size;
    146}
    147
    148size_t get_def_hugetlb_pagesz(void)
    149{
    150	char buf[64];
    151	const char *tag = "Hugepagesize:";
    152	FILE *f;
    153
    154	f = fopen("/proc/meminfo", "r");
    155	TEST_ASSERT(f != NULL, "Error in opening /proc/meminfo");
    156
    157	while (fgets(buf, sizeof(buf), f) != NULL) {
    158		if (strstr(buf, tag) == buf) {
    159			fclose(f);
    160			return strtoull(buf + strlen(tag), NULL, 10) << 10;
    161		}
    162	}
    163
    164	if (feof(f))
    165		TEST_FAIL("HUGETLB is not configured in host kernel");
    166	else
    167		TEST_FAIL("Error in reading /proc/meminfo");
    168
    169	fclose(f);
    170	return 0;
    171}
    172
    173#define ANON_FLAGS	(MAP_PRIVATE | MAP_ANONYMOUS)
    174#define ANON_HUGE_FLAGS	(ANON_FLAGS | MAP_HUGETLB)
    175
    176const struct vm_mem_backing_src_alias *vm_mem_backing_src_alias(uint32_t i)
    177{
    178	static const struct vm_mem_backing_src_alias aliases[] = {
    179		[VM_MEM_SRC_ANONYMOUS] = {
    180			.name = "anonymous",
    181			.flag = ANON_FLAGS,
    182		},
    183		[VM_MEM_SRC_ANONYMOUS_THP] = {
    184			.name = "anonymous_thp",
    185			.flag = ANON_FLAGS,
    186		},
    187		[VM_MEM_SRC_ANONYMOUS_HUGETLB] = {
    188			.name = "anonymous_hugetlb",
    189			.flag = ANON_HUGE_FLAGS,
    190		},
    191		[VM_MEM_SRC_ANONYMOUS_HUGETLB_16KB] = {
    192			.name = "anonymous_hugetlb_16kb",
    193			.flag = ANON_HUGE_FLAGS | MAP_HUGE_16KB,
    194		},
    195		[VM_MEM_SRC_ANONYMOUS_HUGETLB_64KB] = {
    196			.name = "anonymous_hugetlb_64kb",
    197			.flag = ANON_HUGE_FLAGS | MAP_HUGE_64KB,
    198		},
    199		[VM_MEM_SRC_ANONYMOUS_HUGETLB_512KB] = {
    200			.name = "anonymous_hugetlb_512kb",
    201			.flag = ANON_HUGE_FLAGS | MAP_HUGE_512KB,
    202		},
    203		[VM_MEM_SRC_ANONYMOUS_HUGETLB_1MB] = {
    204			.name = "anonymous_hugetlb_1mb",
    205			.flag = ANON_HUGE_FLAGS | MAP_HUGE_1MB,
    206		},
    207		[VM_MEM_SRC_ANONYMOUS_HUGETLB_2MB] = {
    208			.name = "anonymous_hugetlb_2mb",
    209			.flag = ANON_HUGE_FLAGS | MAP_HUGE_2MB,
    210		},
    211		[VM_MEM_SRC_ANONYMOUS_HUGETLB_8MB] = {
    212			.name = "anonymous_hugetlb_8mb",
    213			.flag = ANON_HUGE_FLAGS | MAP_HUGE_8MB,
    214		},
    215		[VM_MEM_SRC_ANONYMOUS_HUGETLB_16MB] = {
    216			.name = "anonymous_hugetlb_16mb",
    217			.flag = ANON_HUGE_FLAGS | MAP_HUGE_16MB,
    218		},
    219		[VM_MEM_SRC_ANONYMOUS_HUGETLB_32MB] = {
    220			.name = "anonymous_hugetlb_32mb",
    221			.flag = ANON_HUGE_FLAGS | MAP_HUGE_32MB,
    222		},
    223		[VM_MEM_SRC_ANONYMOUS_HUGETLB_256MB] = {
    224			.name = "anonymous_hugetlb_256mb",
    225			.flag = ANON_HUGE_FLAGS | MAP_HUGE_256MB,
    226		},
    227		[VM_MEM_SRC_ANONYMOUS_HUGETLB_512MB] = {
    228			.name = "anonymous_hugetlb_512mb",
    229			.flag = ANON_HUGE_FLAGS | MAP_HUGE_512MB,
    230		},
    231		[VM_MEM_SRC_ANONYMOUS_HUGETLB_1GB] = {
    232			.name = "anonymous_hugetlb_1gb",
    233			.flag = ANON_HUGE_FLAGS | MAP_HUGE_1GB,
    234		},
    235		[VM_MEM_SRC_ANONYMOUS_HUGETLB_2GB] = {
    236			.name = "anonymous_hugetlb_2gb",
    237			.flag = ANON_HUGE_FLAGS | MAP_HUGE_2GB,
    238		},
    239		[VM_MEM_SRC_ANONYMOUS_HUGETLB_16GB] = {
    240			.name = "anonymous_hugetlb_16gb",
    241			.flag = ANON_HUGE_FLAGS | MAP_HUGE_16GB,
    242		},
    243		[VM_MEM_SRC_SHMEM] = {
    244			.name = "shmem",
    245			.flag = MAP_SHARED,
    246		},
    247		[VM_MEM_SRC_SHARED_HUGETLB] = {
    248			.name = "shared_hugetlb",
    249			/*
    250			 * No MAP_HUGETLB, we use MFD_HUGETLB instead. Since
    251			 * we're using "file backed" memory, we need to specify
    252			 * this when the FD is created, not when the area is
    253			 * mapped.
    254			 */
    255			.flag = MAP_SHARED,
    256		},
    257	};
    258	_Static_assert(ARRAY_SIZE(aliases) == NUM_SRC_TYPES,
    259		       "Missing new backing src types?");
    260
    261	TEST_ASSERT(i < NUM_SRC_TYPES, "Backing src type ID %d too big", i);
    262
    263	return &aliases[i];
    264}
    265
    266#define MAP_HUGE_PAGE_SIZE(x) (1ULL << ((x >> MAP_HUGE_SHIFT) & MAP_HUGE_MASK))
    267
    268size_t get_backing_src_pagesz(uint32_t i)
    269{
    270	uint32_t flag = vm_mem_backing_src_alias(i)->flag;
    271
    272	switch (i) {
    273	case VM_MEM_SRC_ANONYMOUS:
    274	case VM_MEM_SRC_SHMEM:
    275		return getpagesize();
    276	case VM_MEM_SRC_ANONYMOUS_THP:
    277		return get_trans_hugepagesz();
    278	case VM_MEM_SRC_ANONYMOUS_HUGETLB:
    279	case VM_MEM_SRC_SHARED_HUGETLB:
    280		return get_def_hugetlb_pagesz();
    281	default:
    282		return MAP_HUGE_PAGE_SIZE(flag);
    283	}
    284}
    285
    286bool is_backing_src_hugetlb(uint32_t i)
    287{
    288	return !!(vm_mem_backing_src_alias(i)->flag & MAP_HUGETLB);
    289}
    290
    291static void print_available_backing_src_types(const char *prefix)
    292{
    293	int i;
    294
    295	printf("%sAvailable backing src types:\n", prefix);
    296
    297	for (i = 0; i < NUM_SRC_TYPES; i++)
    298		printf("%s    %s\n", prefix, vm_mem_backing_src_alias(i)->name);
    299}
    300
    301void backing_src_help(const char *flag)
    302{
    303	printf(" %s: specify the type of memory that should be used to\n"
    304	       "     back the guest data region. (default: %s)\n",
    305	       flag, vm_mem_backing_src_alias(DEFAULT_VM_MEM_SRC)->name);
    306	print_available_backing_src_types("     ");
    307}
    308
    309enum vm_mem_backing_src_type parse_backing_src_type(const char *type_name)
    310{
    311	int i;
    312
    313	for (i = 0; i < NUM_SRC_TYPES; i++)
    314		if (!strcmp(type_name, vm_mem_backing_src_alias(i)->name))
    315			return i;
    316
    317	print_available_backing_src_types("");
    318	TEST_FAIL("Unknown backing src type: %s", type_name);
    319	return -1;
    320}
    321
    322long get_run_delay(void)
    323{
    324	char path[64];
    325	long val[2];
    326	FILE *fp;
    327
    328	sprintf(path, "/proc/%ld/schedstat", syscall(SYS_gettid));
    329	fp = fopen(path, "r");
    330	/* Return MIN_RUN_DELAY_NS upon failure just to be safe */
    331	if (fscanf(fp, "%ld %ld ", &val[0], &val[1]) < 2)
    332		val[1] = MIN_RUN_DELAY_NS;
    333	fclose(fp);
    334
    335	return val[1];
    336}