Skip to content

Commit

Permalink
From patchwork series 421697
Browse files Browse the repository at this point in the history
  • Loading branch information
Fox Snowpatch committed Aug 30, 2024
1 parent ddf9a4c commit 9de8378
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 26 deletions.
8 changes: 5 additions & 3 deletions Documentation/ABI/stable/vdso
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ maps an ELF DSO into that program's address space. This DSO is called
the vDSO and it often contains useful and highly-optimized alternatives
to real syscalls.

These functions are called just like ordinary C function according to
your platform's ABI. Call them from a sensible context. (For example,
if you set CS on x86 to something strange, the vDSO functions are
These functions are called according to your platform's ABI. On many
platforms they are called just like ordinary C function. On other platforms
(ex: powerpc) they are called with the same convention as system calls which
is different from ordinary C functions. Call them from a sensible context.
(For example, if you set CS on x86 to something strange, the vDSO functions are
within their rights to crash.) In addition, if you pass a bad
pointer to a vDSO function, you might get SIGSEGV instead of -EFAULT.

Expand Down
3 changes: 2 additions & 1 deletion tools/testing/selftests/vDSO/parse_vdso.c
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,8 @@ void *vdso_sym(const char *version, const char *name)
ELF(Sym) *sym = &vdso_info.symtab[chain];

/* Check for a defined global or weak function w/ right name. */
if (ELF64_ST_TYPE(sym->st_info) != STT_FUNC)
if (ELF64_ST_TYPE(sym->st_info) != STT_FUNC &&
ELF64_ST_TYPE(sym->st_info) != STT_NOTYPE)
continue;
if (ELF64_ST_BIND(sym->st_info) != STB_GLOBAL &&
ELF64_ST_BIND(sym->st_info) != STB_WEAK)
Expand Down
70 changes: 70 additions & 0 deletions tools/testing/selftests/vDSO/vdso_call.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Macro to call vDSO functions
*
* Copyright (C) 2024 Christophe Leroy <[email protected]>, CS GROUP France
*/
#ifndef __VDSO_CALL_H__
#define __VDSO_CALL_H__

#ifdef __powerpc__

#define LOADARGS_1(fn, __arg1) do { \
_r0 = fn; \
_r3 = (long)__arg1; \
} while (0)

#define LOADARGS_2(fn, __arg1, __arg2) do { \
_r0 = fn; \
_r3 = (long)__arg1; \
_r4 = (long)__arg2; \
} while (0)

#define LOADARGS_3(fn, __arg1, __arg2, __arg3) do { \
_r0 = fn; \
_r3 = (long)__arg1; \
_r4 = (long)__arg2; \
_r5 = (long)__arg3; \
} while (0)

#define LOADARGS_5(fn, __arg1, __arg2, __arg3, __arg4, __arg5) do { \
_r0 = fn; \
_r3 = (long)__arg1; \
_r4 = (long)__arg2; \
_r5 = (long)__arg3; \
_r6 = (long)__arg4; \
_r7 = (long)__arg5; \
} while (0)

#define VDSO_CALL(fn, nr, args...) ({ \
register void *_r0 asm ("r0"); \
register long _r3 asm ("r3"); \
register long _r4 asm ("r4"); \
register long _r5 asm ("r5"); \
register long _r6 asm ("r6"); \
register long _r7 asm ("r7"); \
register long _r8 asm ("r8"); \
register long _rval asm ("r3"); \
\
LOADARGS_##nr(fn, args); \
\
asm volatile( \
" mtctr %0\n" \
" bctrl\n" \
" bns+ 1f\n" \
" neg 3, 3\n" \
"1:" \
: "+r" (_r0), "=r" (_r3), "+r" (_r4), "+r" (_r5), \
"+r" (_r6), "+r" (_r7), "+r" (_r8) \
: "r" (_rval) \
: "r9", "r10", "r11", "r12", "cr0", "cr1", "cr5", \
"cr6", "cr7", "xer", "lr", "ctr", "memory" \
); \
_rval; \
})

#else
#define VDSO_CALL(fn, nr, args...) fn(args)
#endif

#endif
6 changes: 3 additions & 3 deletions tools/testing/selftests/vDSO/vdso_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@
#elif defined(__aarch64__)
#define VDSO_VERSION 3
#define VDSO_NAMES 0
#elif defined(__powerpc__)
#elif defined(__powerpc64__)
#define VDSO_VERSION 1
#define VDSO_NAMES 0
#define VDSO_32BIT 1
#elif defined(__powerpc64__)
#elif defined(__powerpc__)
#define VDSO_VERSION 1
#define VDSO_NAMES 0
#define VDSO_32BIT 1
#elif defined (__s390__)
#define VDSO_VERSION 2
#define VDSO_NAMES 0
Expand Down
14 changes: 6 additions & 8 deletions tools/testing/selftests/vDSO/vdso_test_abi.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,8 @@

#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);
#include "vdso_call.h"
#include "parse_vdso.h"

static const char *version;
static const char **name;
Expand Down Expand Up @@ -61,7 +59,7 @@ static void vdso_test_gettimeofday(void)
}

struct timeval tv;
long ret = vdso_gettimeofday(&tv, 0);
long ret = VDSO_CALL(vdso_gettimeofday, 2, &tv, 0);

if (ret == 0) {
ksft_print_msg("The time is %lld.%06lld\n",
Expand All @@ -86,7 +84,7 @@ static void vdso_test_clock_gettime(clockid_t clk_id)
}

struct timespec ts;
long ret = vdso_clock_gettime(clk_id, &ts);
long ret = VDSO_CALL(vdso_clock_gettime, 2, clk_id, &ts);

if (ret == 0) {
ksft_print_msg("The time is %lld.%06lld\n",
Expand All @@ -111,7 +109,7 @@ static void vdso_test_time(void)
return;
}

long ret = vdso_time(NULL);
long ret = VDSO_CALL(vdso_time, 1, NULL);

if (ret > 0) {
ksft_print_msg("The time in hours since January 1, 1970 is %lld\n",
Expand All @@ -138,7 +136,7 @@ static void vdso_test_clock_getres(clockid_t clk_id)
}

struct timespec ts, sys_ts;
long ret = vdso_clock_getres(clk_id, &ts);
long ret = VDSO_CALL(vdso_clock_getres, 2, clk_id, &ts);

if (ret == 0) {
ksft_print_msg("The vdso resolution is %lld %lld\n",
Expand Down
21 changes: 14 additions & 7 deletions tools/testing/selftests/vDSO/vdso_test_correctness.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <limits.h>

#include "vdso_config.h"
#include "vdso_call.h"
#include "../kselftest.h"

static const char **name;
Expand Down Expand Up @@ -114,6 +115,12 @@ static void fill_function_pointers()
if (!vdso)
vdso = dlopen("linux-gate.so.1",
RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
if (!vdso)
vdso = dlopen("linux-vdso32.so.1",
RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
if (!vdso)
vdso = dlopen("linux-vdso64.so.1",
RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
if (!vdso) {
printf("[WARN]\tfailed to find vDSO\n");
return;
Expand Down Expand Up @@ -180,7 +187,7 @@ static void test_getcpu(void)

ret_sys = sys_getcpu(&cpu_sys, &node_sys, 0);
if (vdso_getcpu)
ret_vdso = vdso_getcpu(&cpu_vdso, &node_vdso, 0);
ret_vdso = VDSO_CALL(vdso_getcpu, 3, &cpu_vdso, &node_vdso, 0);
if (vgetcpu)
ret_vsys = vgetcpu(&cpu_vsys, &node_vsys, 0);

Expand Down Expand Up @@ -263,7 +270,7 @@ static void test_one_clock_gettime(int clock, const char *name)

if (sys_clock_gettime(clock, &start) < 0) {
if (errno == EINVAL) {
vdso_ret = vdso_clock_gettime(clock, &vdso);
vdso_ret = VDSO_CALL(vdso_clock_gettime, 2, clock, &vdso);
if (vdso_ret == -EINVAL) {
printf("[OK]\tNo such clock.\n");
} else {
Expand All @@ -276,7 +283,7 @@ static void test_one_clock_gettime(int clock, const char *name)
return;
}

vdso_ret = vdso_clock_gettime(clock, &vdso);
vdso_ret = VDSO_CALL(vdso_clock_gettime, 2, clock, &vdso);
end_ret = sys_clock_gettime(clock, &end);

if (vdso_ret != 0 || end_ret != 0) {
Expand Down Expand Up @@ -325,7 +332,7 @@ static void test_one_clock_gettime64(int clock, const char *name)

if (sys_clock_gettime64(clock, &start) < 0) {
if (errno == EINVAL) {
vdso_ret = vdso_clock_gettime64(clock, &vdso);
vdso_ret = VDSO_CALL(vdso_clock_gettime64, 2, clock, &vdso);
if (vdso_ret == -EINVAL) {
printf("[OK]\tNo such clock.\n");
} else {
Expand All @@ -338,7 +345,7 @@ static void test_one_clock_gettime64(int clock, const char *name)
return;
}

vdso_ret = vdso_clock_gettime64(clock, &vdso);
vdso_ret = VDSO_CALL(vdso_clock_gettime64, 2, clock, &vdso);
end_ret = sys_clock_gettime64(clock, &end);

if (vdso_ret != 0 || end_ret != 0) {
Expand Down Expand Up @@ -395,7 +402,7 @@ static void test_gettimeofday(void)
return;
}

vdso_ret = vdso_gettimeofday(&vdso, &vdso_tz);
vdso_ret = VDSO_CALL(vdso_gettimeofday, 2, &vdso, &vdso_tz);
end_ret = sys_gettimeofday(&end, NULL);

if (vdso_ret != 0 || end_ret != 0) {
Expand Down Expand Up @@ -425,7 +432,7 @@ static void test_gettimeofday(void)
}

/* And make sure that passing NULL for tz doesn't crash. */
vdso_gettimeofday(&vdso, NULL);
VDSO_CALL(vdso_gettimeofday, 2, &vdso, NULL);
}

int main(int argc, char **argv)
Expand Down
3 changes: 2 additions & 1 deletion tools/testing/selftests/vDSO/vdso_test_getcpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "../kselftest.h"
#include "parse_vdso.h"
#include "vdso_config.h"
#include "vdso_call.h"

struct getcpu_cache;
typedef long (*getcpu_t)(unsigned int *, unsigned int *,
Expand Down Expand Up @@ -42,7 +43,7 @@ int main(int argc, char **argv)
return KSFT_SKIP;
}

ret = get_cpu(&cpu, &node, 0);
ret = VDSO_CALL(get_cpu, 3, &cpu, &node, 0);
if (ret == 0) {
printf("Running on CPU %u node %u\n", cpu, node);
} else {
Expand Down
5 changes: 3 additions & 2 deletions tools/testing/selftests/vDSO/vdso_test_getrandom.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include "../kselftest.h"
#include "parse_vdso.h"
#include "vdso_call.h"

#ifndef timespecsub
#define timespecsub(tsp, usp, vsp) \
Expand Down Expand Up @@ -120,7 +121,7 @@ static void vgetrandom_init(void)
printf("__vdso_getrandom is missing!\n");
exit(KSFT_FAIL);
}
if (grnd_ctx.fn(NULL, 0, 0, &grnd_ctx.params, ~0UL) != 0) {
if (VDSO_CALL(grnd_ctx.fn, 5, NULL, 0, 0, &grnd_ctx.params, ~0UL) != 0) {
printf("failed to fetch vgetrandom params!\n");
exit(KSFT_FAIL);
}
Expand All @@ -143,7 +144,7 @@ static ssize_t vgetrandom(void *buf, size_t len, unsigned long flags)
exit(KSFT_FAIL);
}
}
return grnd_ctx.fn(buf, len, flags, state, grnd_ctx.params.size_of_opaque_state);
return VDSO_CALL(grnd_ctx.fn, 5, buf, len, flags, state, grnd_ctx.params.size_of_opaque_state);
}

enum { TRIALS = 25000000, THREADS = 256 };
Expand Down
3 changes: 2 additions & 1 deletion tools/testing/selftests/vDSO/vdso_test_gettimeofday.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "../kselftest.h"
#include "parse_vdso.h"
#include "vdso_config.h"
#include "vdso_call.h"

int main(int argc, char **argv)
{
Expand All @@ -43,7 +44,7 @@ int main(int argc, char **argv)
}

struct timeval tv;
long ret = gtod(&tv, 0);
long ret = VDSO_CALL(gtod, 2, &tv, 0);

if (ret == 0) {
printf("The time is %lld.%06lld\n",
Expand Down

0 comments on commit 9de8378

Please sign in to comment.