linux-kselftest-next-5.11-rc1

This kselftest update for Linux 5.11-rc1 consists of:
 
 - Much needed gpio test Makefile cleanup to various problems with
   test dependencies and build errors from Michael Ellerman
 
 - Enabling vDSO test on non x86 platforms from Vincenzo Frascino
 
 - Fix intel_pstate to replace deprecated ftime() usages with
   clock_gettime() from Tommi Rantala
 
 - cgroup test build fix on older releases from Sachin Sant
 
 - A couple of spelling mistake fixes
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEPZKym/RZuOCGeA/kCwJExA0NQxwFAl/ZFxIACgkQCwJExA0N
 QxyMPA//YHMceV0Q/fbqWeLG2ujs3WaARm+AIpx0oFckHQrEwWt/r5Vl2f9CwWI/
 lXqsVI/bKpuoQsaMG15p7zA+jp+28+oXNQSdSLVJG+nfPcDhzIWbdb+UM905e6mJ
 SWBQaB3MRGIojUaxT8mCGMK2Edmm/tJH2yQdyXic7FcFmKKQQo92wxg4QD3YU9BK
 EhxfZZMmzMw1CtUlvx8PPEviF4IjU5X7AnHlAIx/Tw8edfRQ72UGjP9g6ynW4BYW
 c2yLuB2SDic9YzGHCqtzw+7H6OokWpYjIvicFeTHhOaRRZ/0HH168EngZB5B1ELv
 K3fJzls6eXdtYGGMYDNf640naTzsbjCg+i65nkQsvlkiZK1ow5NMgfKgJlpKBBqf
 9pFLUnO8cegmgS+Iu+PXY6a7Rgg7XVKpkDCRGRix+hE5Ooc82w42UnWtO52rKG0f
 vawprd465wnm+/6VpidnEteEhQAx4qUoh6AIdowNDLXEAWlYWcb1IXHeTFufY9xU
 YWi52P813dyTzkGyFfNH+ardlQihLVZW2zlPY0PfxDeSfyaIVyIh06pHMB1uG2qa
 NQ+1OH7p2ACEq8CNhlqeHXmb1po2VSB5ChP7aVvGUajdfaXE5apeRraHhiT/Q9ls
 24xyV3upUEOTrWl/2AdHMjQ/ukxgCaiLyPfyL+BJhTk4CSI/hnc=
 =7+0j
 -----END PGP SIGNATURE-----

Merge tag 'linux-kselftest-next-5.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest

Pull Kselftest updates from Shuah Khan:

 - Much needed gpio test Makefile cleanup to various problems with test
   dependencies and build errors from Michael Ellerman

 - Enabling vDSO test on non x86 platforms from Vincenzo Frascino

 - Fix intel_pstate to replace deprecated ftime() usages with
   clock_gettime() from Tommi Rantala

 - cgroup test build fix on older releases from Sachin Sant

 - A couple of spelling mistake fixes

* tag 'linux-kselftest-next-5.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest:
  selftests/cgroup: Fix build on older distros
  selftests/run_kselftest.sh: fix dry-run typo
  tool: selftests: fix spelling typo of 'writting'
  selftests/memfd: Fix implicit declaration warnings
  selftests: intel_pstate: ftime() is deprecated
  selftests/gpio: Add to CLEAN rule rather than overriding
  selftests/gpio: Fix build when source tree is read only
  selftests/gpio: Move include of lib.mk up
  selftests/gpio: Use TEST_GEN_PROGS_EXTENDED
  kselftest: Extend vdso correctness test to clock_gettime64
  kselftest: Move test_vdso to the vDSO test suite
  kselftest: Extend vDSO selftest to clock_getres
  kselftest: Extend vDSO selftest
  kselftest: Enable vDSO test on non x86 platforms
This commit is contained in:
Linus Torvalds 2020-12-16 00:17:58 -08:00
commit 7194850efa
14 changed files with 622 additions and 35 deletions

View file

@ -66,6 +66,7 @@ endif
TARGETS += tmpfs
TARGETS += tpm2
TARGETS += user
TARGETS += vDSO
TARGETS += vm
TARGETS += x86
TARGETS += zram

View file

@ -337,13 +337,13 @@ pid_t clone_into_cgroup(int cgroup_fd)
#ifdef CLONE_ARGS_SIZE_VER2
pid_t pid;
struct clone_args args = {
struct __clone_args args = {
.flags = CLONE_INTO_CGROUP,
.exit_signal = SIGCHLD,
.cgroup = cgroup_fd,
};
pid = sys_clone3(&args, sizeof(struct clone_args));
pid = sys_clone3(&args, sizeof(struct __clone_args));
/*
* Verify that this is a genuine test failure:
* ENOSYS -> clone3() not available

View file

@ -11,22 +11,21 @@ LDLIBS += $(VAR_LDLIBS)
TEST_PROGS := gpio-mockup.sh
TEST_FILES := gpio-mockup-sysfs.sh
TEST_PROGS_EXTENDED := gpio-mockup-chardev
GPIODIR := $(realpath ../../../gpio)
GPIOOBJ := gpio-utils.o
all: $(TEST_PROGS_EXTENDED)
override define CLEAN
$(RM) $(TEST_PROGS_EXTENDED)
$(MAKE) -C $(GPIODIR) OUTPUT=$(GPIODIR)/ clean
endef
TEST_GEN_PROGS_EXTENDED := gpio-mockup-chardev
KSFT_KHDR_INSTALL := 1
include ../lib.mk
$(TEST_PROGS_EXTENDED): $(GPIODIR)/$(GPIOOBJ)
GPIODIR := $(realpath ../../../gpio)
GPIOOUT := $(OUTPUT)/tools-gpio/
GPIOOBJ := $(GPIOOUT)/gpio-utils.o
$(GPIODIR)/$(GPIOOBJ):
$(MAKE) OUTPUT=$(GPIODIR)/ -C $(GPIODIR)
CLEAN += ; $(RM) -rf $(GPIOOUT)
$(TEST_GEN_PROGS_EXTENDED): $(GPIOOBJ)
$(GPIOOUT):
mkdir -p $@
$(GPIOOBJ): $(GPIOOUT)
$(MAKE) OUTPUT=$(GPIOOUT) -C $(GPIODIR)

View file

@ -10,8 +10,12 @@
#include <sched.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include "../kselftest.h"
#define MSEC_PER_SEC 1000L
#define NSEC_PER_MSEC 1000000L
void usage(char *name) {
printf ("Usage: %s cpunum\n", name);
}
@ -22,7 +26,7 @@ int main(int argc, char **argv) {
long long tsc, old_tsc, new_tsc;
long long aperf, old_aperf, new_aperf;
long long mperf, old_mperf, new_mperf;
struct timeb before, after;
struct timespec before, after;
long long int start, finish, total;
cpu_set_t cpuset;
@ -55,7 +59,10 @@ int main(int argc, char **argv) {
return 1;
}
ftime(&before);
if (clock_gettime(CLOCK_MONOTONIC, &before) < 0) {
perror("clock_gettime");
return 1;
}
pread(fd, &old_tsc, sizeof(old_tsc), 0x10);
pread(fd, &old_aperf, sizeof(old_mperf), 0xe7);
pread(fd, &old_mperf, sizeof(old_aperf), 0xe8);
@ -64,7 +71,10 @@ int main(int argc, char **argv) {
sqrt(i);
}
ftime(&after);
if (clock_gettime(CLOCK_MONOTONIC, &after) < 0) {
perror("clock_gettime");
return 1;
}
pread(fd, &new_tsc, sizeof(new_tsc), 0x10);
pread(fd, &new_aperf, sizeof(new_mperf), 0xe7);
pread(fd, &new_mperf, sizeof(new_aperf), 0xe8);
@ -73,11 +83,11 @@ int main(int argc, char **argv) {
aperf = new_aperf-old_aperf;
mperf = new_mperf-old_mperf;
start = before.time*1000 + before.millitm;
finish = after.time*1000 + after.millitm;
start = before.tv_sec*MSEC_PER_SEC + before.tv_nsec/NSEC_PER_MSEC;
finish = after.tv_sec*MSEC_PER_SEC + after.tv_nsec/NSEC_PER_MSEC;
total = finish - start;
printf("runTime: %4.2f\n", 1.0*total/1000);
printf("runTime: %4.2f\n", 1.0*total/MSEC_PER_SEC);
printf("freq: %7.0f\n", tsc / (1.0*aperf / (1.0 * mperf)) / total);
return 0;
}

View file

@ -20,7 +20,7 @@
#include <inttypes.h>
#include <limits.h>
#include <linux/falloc.h>
#include <linux/fcntl.h>
#include <fcntl.h>
#include <linux/memfd.h>
#include <sched.h>
#include <stdio.h>

View file

@ -6,7 +6,7 @@
#include <inttypes.h>
#include <limits.h>
#include <linux/falloc.h>
#include <linux/fcntl.h>
#include <fcntl.h>
#include <linux/memfd.h>
#include <sched.h>
#include <stdio.h>

View file

@ -48,7 +48,7 @@ while true; do
-l | --list)
echo "$available"
exit 0 ;;
-n | --dry-run)
-d | --dry-run)
dryrun="echo"
shift ;;
-h | --help)

View file

@ -5,13 +5,16 @@ uname_M := $(shell uname -m 2>/dev/null || echo not)
ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/x86/ -e s/x86_64/x86/)
TEST_GEN_PROGS := $(OUTPUT)/vdso_test_gettimeofday $(OUTPUT)/vdso_test_getcpu
ifeq ($(ARCH),x86)
TEST_GEN_PROGS += $(OUTPUT)/vdso_test_abi
TEST_GEN_PROGS += $(OUTPUT)/vdso_test_clock_getres
ifeq ($(ARCH),$(filter $(ARCH),x86 x86_64))
TEST_GEN_PROGS += $(OUTPUT)/vdso_standalone_test_x86
endif
TEST_GEN_PROGS += $(OUTPUT)/vdso_test_correctness
ifndef CROSS_COMPILE
CFLAGS := -std=gnu99
CFLAGS_vdso_standalone_test_x86 := -nostdlib -fno-asynchronous-unwind-tables -fno-stack-protector
LDFLAGS_vdso_test_correctness := -ldl
ifeq ($(CONFIG_X86_32),y)
LDLIBS += -lgcc_s
endif
@ -19,9 +22,14 @@ endif
all: $(TEST_GEN_PROGS)
$(OUTPUT)/vdso_test_gettimeofday: parse_vdso.c vdso_test_gettimeofday.c
$(OUTPUT)/vdso_test_getcpu: parse_vdso.c vdso_test_getcpu.c
$(OUTPUT)/vdso_test_abi: parse_vdso.c vdso_test_abi.c
$(OUTPUT)/vdso_test_clock_getres: vdso_test_clock_getres.c
$(OUTPUT)/vdso_standalone_test_x86: vdso_standalone_test_x86.c parse_vdso.c
$(CC) $(CFLAGS) $(CFLAGS_vdso_standalone_test_x86) \
vdso_standalone_test_x86.c parse_vdso.c \
-o $@
endif
$(OUTPUT)/vdso_test_correctness: vdso_test_correctness.c
$(CC) $(CFLAGS) \
vdso_test_correctness.c \
-o $@ \
$(LDFLAGS_vdso_test_correctness)

View file

@ -0,0 +1,92 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* vdso_config.h: Configuration options for vDSO tests.
* Copyright (c) 2019 Arm Ltd.
*/
#ifndef __VDSO_CONFIG_H__
#define __VDSO_CONFIG_H__
/*
* Each architecture exports its vDSO implementation with different names
* and a different version from the others, so we need to handle it as a
* special case.
*/
#if defined(__arm__)
#define VDSO_VERSION 0
#define VDSO_NAMES 1
#define VDSO_32BIT 1
#elif defined(__aarch64__)
#define VDSO_VERSION 3
#define VDSO_NAMES 0
#elif defined(__powerpc__)
#define VDSO_VERSION 1
#define VDSO_NAMES 0
#define VDSO_32BIT 1
#elif defined(__powerpc64__)
#define VDSO_VERSION 1
#define VDSO_NAMES 0
#elif defined (__s390__)
#define VDSO_VERSION 2
#define VDSO_NAMES 0
#define VDSO_32BIT 1
#elif defined (__s390X__)
#define VDSO_VERSION 2
#define VDSO_NAMES 0
#elif defined(__mips__)
#define VDSO_VERSION 0
#define VDSO_NAMES 1
#define VDSO_32BIT 1
#elif defined(__sparc__)
#define VDSO_VERSION 0
#define VDSO_NAMES 1
#define VDSO_32BIT 1
#elif defined(__i386__)
#define VDSO_VERSION 0
#define VDSO_NAMES 1
#define VDSO_32BIT 1
#elif defined(__x86_64__)
#define VDSO_VERSION 0
#define VDSO_NAMES 1
#elif defined(__riscv__)
#define VDSO_VERSION 5
#define VDSO_NAMES 1
#define VDSO_32BIT 1
#else /* nds32 */
#define VDSO_VERSION 4
#define VDSO_NAMES 1
#define VDSO_32BIT 1
#endif
static const char *versions[6] = {
"LINUX_2.6",
"LINUX_2.6.15",
"LINUX_2.6.29",
"LINUX_2.6.39",
"LINUX_4",
"LINUX_4.15",
};
static const char *names[2][6] = {
{
"__kernel_gettimeofday",
"__kernel_clock_gettime",
"__kernel_time",
"__kernel_clock_getres",
"__kernel_getcpu",
#if defined(VDSO_32BIT)
"__kernel_clock_gettime64",
#endif
},
{
"__vdso_gettimeofday",
"__vdso_clock_gettime",
"__vdso_time",
"__vdso_clock_getres",
"__vdso_getcpu",
#if defined(VDSO_32BIT)
"__vdso_clock_gettime64",
#endif
},
};
#endif /* __VDSO_CONFIG_H__ */

View file

@ -0,0 +1,244 @@
// SPDX-License-Identifier: GPL-2.0
/*
* vdso_full_test.c: Sample code to test all the timers.
* Copyright (c) 2019 Arm Ltd.
*
* Compile with:
* gcc -std=gnu99 vdso_full_test.c parse_vdso.c
*
*/
#include <stdint.h>
#include <elf.h>
#include <stdio.h>
#include <time.h>
#include <sys/auxv.h>
#include <sys/time.h>
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
#include "../kselftest.h"
#include "vdso_config.h"
extern void *vdso_sym(const char *version, const char *name);
extern void vdso_init_from_sysinfo_ehdr(uintptr_t base);
extern void vdso_init_from_auxv(void *auxv);
static const char *version;
static const char **name;
typedef long (*vdso_gettimeofday_t)(struct timeval *tv, struct timezone *tz);
typedef long (*vdso_clock_gettime_t)(clockid_t clk_id, struct timespec *ts);
typedef long (*vdso_clock_getres_t)(clockid_t clk_id, struct timespec *ts);
typedef time_t (*vdso_time_t)(time_t *t);
static int vdso_test_gettimeofday(void)
{
/* Find gettimeofday. */
vdso_gettimeofday_t vdso_gettimeofday =
(vdso_gettimeofday_t)vdso_sym(version, name[0]);
if (!vdso_gettimeofday) {
printf("Could not find %s\n", name[0]);
return KSFT_SKIP;
}
struct timeval tv;
long ret = vdso_gettimeofday(&tv, 0);
if (ret == 0) {
printf("The time is %lld.%06lld\n",
(long long)tv.tv_sec, (long long)tv.tv_usec);
} else {
printf("%s failed\n", name[0]);
return KSFT_FAIL;
}
return KSFT_PASS;
}
static int vdso_test_clock_gettime(clockid_t clk_id)
{
/* Find clock_gettime. */
vdso_clock_gettime_t vdso_clock_gettime =
(vdso_clock_gettime_t)vdso_sym(version, name[1]);
if (!vdso_clock_gettime) {
printf("Could not find %s\n", name[1]);
return KSFT_SKIP;
}
struct timespec ts;
long ret = vdso_clock_gettime(clk_id, &ts);
if (ret == 0) {
printf("The time is %lld.%06lld\n",
(long long)ts.tv_sec, (long long)ts.tv_nsec);
} else {
printf("%s failed\n", name[1]);
return KSFT_FAIL;
}
return KSFT_PASS;
}
static int vdso_test_time(void)
{
/* Find time. */
vdso_time_t vdso_time =
(vdso_time_t)vdso_sym(version, name[2]);
if (!vdso_time) {
printf("Could not find %s\n", name[2]);
return KSFT_SKIP;
}
long ret = vdso_time(NULL);
if (ret > 0) {
printf("The time in hours since January 1, 1970 is %lld\n",
(long long)(ret / 3600));
} else {
printf("%s failed\n", name[2]);
return KSFT_FAIL;
}
return KSFT_PASS;
}
static int vdso_test_clock_getres(clockid_t clk_id)
{
/* Find clock_getres. */
vdso_clock_getres_t vdso_clock_getres =
(vdso_clock_getres_t)vdso_sym(version, name[3]);
if (!vdso_clock_getres) {
printf("Could not find %s\n", name[3]);
return KSFT_SKIP;
}
struct timespec ts, sys_ts;
long ret = vdso_clock_getres(clk_id, &ts);
if (ret == 0) {
printf("The resolution is %lld %lld\n",
(long long)ts.tv_sec, (long long)ts.tv_nsec);
} else {
printf("%s failed\n", name[3]);
return KSFT_FAIL;
}
ret = syscall(SYS_clock_getres, clk_id, &sys_ts);
if ((sys_ts.tv_sec != ts.tv_sec) || (sys_ts.tv_nsec != ts.tv_nsec)) {
printf("%s failed\n", name[3]);
return KSFT_FAIL;
}
return KSFT_PASS;
}
const char *vdso_clock_name[12] = {
"CLOCK_REALTIME",
"CLOCK_MONOTONIC",
"CLOCK_PROCESS_CPUTIME_ID",
"CLOCK_THREAD_CPUTIME_ID",
"CLOCK_MONOTONIC_RAW",
"CLOCK_REALTIME_COARSE",
"CLOCK_MONOTONIC_COARSE",
"CLOCK_BOOTTIME",
"CLOCK_REALTIME_ALARM",
"CLOCK_BOOTTIME_ALARM",
"CLOCK_SGI_CYCLE",
"CLOCK_TAI",
};
/*
* This function calls vdso_test_clock_gettime and vdso_test_clock_getres
* with different values for clock_id.
*/
static inline int vdso_test_clock(clockid_t clock_id)
{
int ret0, ret1;
ret0 = vdso_test_clock_gettime(clock_id);
/* A skipped test is considered passed */
if (ret0 == KSFT_SKIP)
ret0 = KSFT_PASS;
ret1 = vdso_test_clock_getres(clock_id);
/* A skipped test is considered passed */
if (ret1 == KSFT_SKIP)
ret1 = KSFT_PASS;
ret0 += ret1;
printf("clock_id: %s", vdso_clock_name[clock_id]);
if (ret0 > 0)
printf(" [FAIL]\n");
else
printf(" [PASS]\n");
return ret0;
}
int main(int argc, char **argv)
{
unsigned long sysinfo_ehdr = getauxval(AT_SYSINFO_EHDR);
int ret;
if (!sysinfo_ehdr) {
printf("AT_SYSINFO_EHDR is not present!\n");
return KSFT_SKIP;
}
version = versions[VDSO_VERSION];
name = (const char **)&names[VDSO_NAMES];
printf("[vDSO kselftest] VDSO_VERSION: %s\n", version);
vdso_init_from_sysinfo_ehdr(getauxval(AT_SYSINFO_EHDR));
ret = vdso_test_gettimeofday();
#if _POSIX_TIMERS > 0
#ifdef CLOCK_REALTIME
ret += vdso_test_clock(CLOCK_REALTIME);
#endif
#ifdef CLOCK_BOOTTIME
ret += vdso_test_clock(CLOCK_BOOTTIME);
#endif
#ifdef CLOCK_TAI
ret += vdso_test_clock(CLOCK_TAI);
#endif
#ifdef CLOCK_REALTIME_COARSE
ret += vdso_test_clock(CLOCK_REALTIME_COARSE);
#endif
#ifdef CLOCK_MONOTONIC
ret += vdso_test_clock(CLOCK_MONOTONIC);
#endif
#ifdef CLOCK_MONOTONIC_RAW
ret += vdso_test_clock(CLOCK_MONOTONIC_RAW);
#endif
#ifdef CLOCK_MONOTONIC_COARSE
ret += vdso_test_clock(CLOCK_MONOTONIC_COARSE);
#endif
#endif
ret += vdso_test_time();
if (ret > 0)
return KSFT_FAIL;
return KSFT_PASS;
}

View file

@ -0,0 +1,124 @@
// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
/*
* vdso_clock_getres.c: Sample code to test clock_getres.
* Copyright (c) 2019 Arm Ltd.
*
* Compile with:
* gcc -std=gnu99 vdso_clock_getres.c
*
* Tested on ARM, ARM64, MIPS32, x86 (32-bit and 64-bit),
* Power (32-bit and 64-bit), S390x (32-bit and 64-bit).
* Might work on other architectures.
*/
#define _GNU_SOURCE
#include <elf.h>
#include <err.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/auxv.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/syscall.h>
#include "../kselftest.h"
static long syscall_clock_getres(clockid_t _clkid, struct timespec *_ts)
{
long ret;
ret = syscall(SYS_clock_getres, _clkid, _ts);
return ret;
}
const char *vdso_clock_name[12] = {
"CLOCK_REALTIME",
"CLOCK_MONOTONIC",
"CLOCK_PROCESS_CPUTIME_ID",
"CLOCK_THREAD_CPUTIME_ID",
"CLOCK_MONOTONIC_RAW",
"CLOCK_REALTIME_COARSE",
"CLOCK_MONOTONIC_COARSE",
"CLOCK_BOOTTIME",
"CLOCK_REALTIME_ALARM",
"CLOCK_BOOTTIME_ALARM",
"CLOCK_SGI_CYCLE",
"CLOCK_TAI",
};
/*
* This function calls clock_getres in vdso and by system call
* with different values for clock_id.
*
* Example of output:
*
* clock_id: CLOCK_REALTIME [PASS]
* clock_id: CLOCK_BOOTTIME [PASS]
* clock_id: CLOCK_TAI [PASS]
* clock_id: CLOCK_REALTIME_COARSE [PASS]
* clock_id: CLOCK_MONOTONIC [PASS]
* clock_id: CLOCK_MONOTONIC_RAW [PASS]
* clock_id: CLOCK_MONOTONIC_COARSE [PASS]
*/
static inline int vdso_test_clock(unsigned int clock_id)
{
struct timespec x, y;
printf("clock_id: %s", vdso_clock_name[clock_id]);
clock_getres(clock_id, &x);
syscall_clock_getres(clock_id, &y);
if ((x.tv_sec != y.tv_sec) || (x.tv_nsec != y.tv_nsec)) {
printf(" [FAIL]\n");
return KSFT_FAIL;
}
printf(" [PASS]\n");
return KSFT_PASS;
}
int main(int argc, char **argv)
{
int ret;
#if _POSIX_TIMERS > 0
#ifdef CLOCK_REALTIME
ret = vdso_test_clock(CLOCK_REALTIME);
#endif
#ifdef CLOCK_BOOTTIME
ret += vdso_test_clock(CLOCK_BOOTTIME);
#endif
#ifdef CLOCK_TAI
ret += vdso_test_clock(CLOCK_TAI);
#endif
#ifdef CLOCK_REALTIME_COARSE
ret += vdso_test_clock(CLOCK_REALTIME_COARSE);
#endif
#ifdef CLOCK_MONOTONIC
ret += vdso_test_clock(CLOCK_MONOTONIC);
#endif
#ifdef CLOCK_MONOTONIC_RAW
ret += vdso_test_clock(CLOCK_MONOTONIC_RAW);
#endif
#ifdef CLOCK_MONOTONIC_COARSE
ret += vdso_test_clock(CLOCK_MONOTONIC_COARSE);
#endif
#endif
if (ret > 0)
return KSFT_FAIL;
return KSFT_PASS;
}

View file

@ -19,6 +19,10 @@
#include <stdbool.h>
#include <limits.h>
#include "vdso_config.h"
static const char **name;
#ifndef SYS_getcpu
# ifdef __x86_64__
# define SYS_getcpu 309
@ -27,6 +31,17 @@
# endif
#endif
#ifndef __NR_clock_gettime64
#define __NR_clock_gettime64 403
#endif
#ifndef __kernel_timespec
struct __kernel_timespec {
long long tv_sec;
long long tv_nsec;
};
#endif
/* max length of lines in /proc/self/maps - anything longer is skipped here */
#define MAPS_LINE_LEN 128
@ -36,6 +51,10 @@ typedef int (*vgettime_t)(clockid_t, struct timespec *);
vgettime_t vdso_clock_gettime;
typedef int (*vgettime64_t)(clockid_t, struct __kernel_timespec *);
vgettime64_t vdso_clock_gettime64;
typedef long (*vgtod_t)(struct timeval *tv, struct timezone *tz);
vgtod_t vdso_gettimeofday;
@ -99,17 +118,23 @@ static void fill_function_pointers()
return;
}
vdso_getcpu = (getcpu_t)dlsym(vdso, "__vdso_getcpu");
vdso_getcpu = (getcpu_t)dlsym(vdso, name[4]);
if (!vdso_getcpu)
printf("Warning: failed to find getcpu in vDSO\n");
vgetcpu = (getcpu_t) vsyscall_getcpu();
vdso_clock_gettime = (vgettime_t)dlsym(vdso, "__vdso_clock_gettime");
vdso_clock_gettime = (vgettime_t)dlsym(vdso, name[1]);
if (!vdso_clock_gettime)
printf("Warning: failed to find clock_gettime in vDSO\n");
vdso_gettimeofday = (vgtod_t)dlsym(vdso, "__vdso_gettimeofday");
#if defined(VDSO_32BIT)
vdso_clock_gettime64 = (vgettime64_t)dlsym(vdso, name[5]);
if (!vdso_clock_gettime64)
printf("Warning: failed to find clock_gettime64 in vDSO\n");
#endif
vdso_gettimeofday = (vgtod_t)dlsym(vdso, name[0]);
if (!vdso_gettimeofday)
printf("Warning: failed to find gettimeofday in vDSO\n");
@ -126,6 +151,11 @@ static inline int sys_clock_gettime(clockid_t id, struct timespec *ts)
return syscall(__NR_clock_gettime, id, ts);
}
static inline int sys_clock_gettime64(clockid_t id, struct __kernel_timespec *ts)
{
return syscall(__NR_clock_gettime64, id, ts);
}
static inline int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
{
return syscall(__NR_gettimeofday, tv, tz);
@ -191,6 +221,15 @@ static bool ts_leq(const struct timespec *a, const struct timespec *b)
return a->tv_nsec <= b->tv_nsec;
}
static bool ts64_leq(const struct __kernel_timespec *a,
const struct __kernel_timespec *b)
{
if (a->tv_sec != b->tv_sec)
return a->tv_sec < b->tv_sec;
else
return a->tv_nsec <= b->tv_nsec;
}
static bool tv_leq(const struct timeval *a, const struct timeval *b)
{
if (a->tv_sec != b->tv_sec)
@ -254,7 +293,10 @@ static void test_one_clock_gettime(int clock, const char *name)
if (!ts_leq(&start, &vdso) || !ts_leq(&vdso, &end)) {
printf("[FAIL]\tTimes are out of sequence\n");
nerrs++;
return;
}
printf("[OK]\tTest Passed.\n");
}
static void test_clock_gettime(void)
@ -275,6 +317,70 @@ static void test_clock_gettime(void)
test_one_clock_gettime(INT_MAX, "invalid");
}
static void test_one_clock_gettime64(int clock, const char *name)
{
struct __kernel_timespec start, vdso, end;
int vdso_ret, end_ret;
printf("[RUN]\tTesting clock_gettime64 for clock %s (%d)...\n", name, clock);
if (sys_clock_gettime64(clock, &start) < 0) {
if (errno == EINVAL) {
vdso_ret = vdso_clock_gettime64(clock, &vdso);
if (vdso_ret == -EINVAL) {
printf("[OK]\tNo such clock.\n");
} else {
printf("[FAIL]\tNo such clock, but __vdso_clock_gettime64 returned %d\n", vdso_ret);
nerrs++;
}
} else {
printf("[WARN]\t clock_gettime64(%d) syscall returned error %d\n", clock, errno);
}
return;
}
vdso_ret = vdso_clock_gettime64(clock, &vdso);
end_ret = sys_clock_gettime64(clock, &end);
if (vdso_ret != 0 || end_ret != 0) {
printf("[FAIL]\tvDSO returned %d, syscall errno=%d\n",
vdso_ret, errno);
nerrs++;
return;
}
printf("\t%llu.%09ld %llu.%09ld %llu.%09ld\n",
(unsigned long long)start.tv_sec, start.tv_nsec,
(unsigned long long)vdso.tv_sec, vdso.tv_nsec,
(unsigned long long)end.tv_sec, end.tv_nsec);
if (!ts64_leq(&start, &vdso) || !ts64_leq(&vdso, &end)) {
printf("[FAIL]\tTimes are out of sequence\n");
nerrs++;
return;
}
printf("[OK]\tTest Passed.\n");
}
static void test_clock_gettime64(void)
{
if (!vdso_clock_gettime64) {
printf("[SKIP]\tNo vDSO, so skipping clock_gettime64() tests\n");
return;
}
for (int clock = 0; clock < sizeof(clocknames) / sizeof(clocknames[0]);
clock++) {
test_one_clock_gettime64(clock, clocknames[clock]);
}
/* Also test some invalid clock ids */
test_one_clock_gettime64(-1, "invalid");
test_one_clock_gettime64(INT_MIN, "invalid");
test_one_clock_gettime64(INT_MAX, "invalid");
}
static void test_gettimeofday(void)
{
struct timeval start, vdso, end;
@ -327,9 +433,12 @@ static void test_gettimeofday(void)
int main(int argc, char **argv)
{
name = (const char **)&names[VDSO_NAMES];
fill_function_pointers();
test_clock_gettime();
test_clock_gettime64();
test_gettimeofday();
/*

View file

@ -906,7 +906,7 @@ static int faulting_process(int signal_test)
count_verify[nr]);
}
/*
* Trigger write protection if there is by writting
* Trigger write protection if there is by writing
* the same value back.
*/
*area_count(area_dst, nr) = count;
@ -934,7 +934,7 @@ static int faulting_process(int signal_test)
count_verify[nr]); exit(1);
}
/*
* Trigger write protection if there is by writting
* Trigger write protection if there is by writing
* the same value back.
*/
*area_count(area_dst, nr) = count;

View file

@ -12,7 +12,7 @@ CAN_BUILD_WITH_NOPIE := $(shell ./check_cc.sh $(CC) trivial_program.c -no-pie)
TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt test_mremap_vdso \
check_initial_reg_state sigreturn iopl ioperm \
test_vdso test_vsyscall mov_ss_trap \
test_vsyscall mov_ss_trap \
syscall_arg_fault fsgsbase_restore
TARGETS_C_32BIT_ONLY := entry_from_vm86 test_syscall_vdso unwind_vdso \
test_FCMOV test_FCOMI test_FISTTP \