Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/x86: Add test_vdso to test getcpu()

I'll eventually add tests for more vDSO functions here.

Signed-off-by: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Megha <megha.dey@intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/945cd29901a62a3cc6ea7d6ee5e389ab1ec1ac0c.1479320367.git.luto@kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>

authored by

Andy Lutomirski and committed by
Ingo Molnar
3200ca80 a582c540

+124 -1
+1 -1
tools/testing/selftests/x86/Makefile
··· 6 6 7 7 TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_syscall test_mremap_vdso \ 8 8 check_initial_reg_state sigreturn ldt_gdt iopl \ 9 - protection_keys 9 + protection_keys test_vdso 10 10 TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso unwind_vdso \ 11 11 test_FCMOV test_FCOMI test_FISTTP \ 12 12 vdso_restorer
+123
tools/testing/selftests/x86/test_vdso.c
··· 1 + /* 2 + * ldt_gdt.c - Test cases for LDT and GDT access 3 + * Copyright (c) 2011-2015 Andrew Lutomirski 4 + */ 5 + 6 + #define _GNU_SOURCE 7 + 8 + #include <stdio.h> 9 + #include <sys/time.h> 10 + #include <time.h> 11 + #include <stdlib.h> 12 + #include <unistd.h> 13 + #include <sys/syscall.h> 14 + #include <dlfcn.h> 15 + #include <string.h> 16 + #include <errno.h> 17 + #include <sched.h> 18 + #include <stdbool.h> 19 + 20 + #ifndef SYS_getcpu 21 + # ifdef __x86_64__ 22 + # define SYS_getcpu 309 23 + # else 24 + # define SYS_getcpu 318 25 + # endif 26 + #endif 27 + 28 + int nerrs = 0; 29 + 30 + #ifdef __x86_64__ 31 + # define VSYS(x) (x) 32 + #else 33 + # define VSYS(x) 0 34 + #endif 35 + 36 + typedef long (*getcpu_t)(unsigned *, unsigned *, void *); 37 + 38 + const getcpu_t vgetcpu = (getcpu_t)VSYS(0xffffffffff600800); 39 + getcpu_t vdso_getcpu; 40 + 41 + void fill_function_pointers() 42 + { 43 + void *vdso = dlopen("linux-vdso.so.1", 44 + RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); 45 + if (!vdso) 46 + vdso = dlopen("linux-gate.so.1", 47 + RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); 48 + if (!vdso) { 49 + printf("[WARN]\tfailed to find vDSO\n"); 50 + return; 51 + } 52 + 53 + vdso_getcpu = (getcpu_t)dlsym(vdso, "__vdso_getcpu"); 54 + if (!vdso_getcpu) 55 + printf("Warning: failed to find getcpu in vDSO\n"); 56 + } 57 + 58 + static long sys_getcpu(unsigned * cpu, unsigned * node, 59 + void* cache) 60 + { 61 + return syscall(__NR_getcpu, cpu, node, cache); 62 + } 63 + 64 + static void test_getcpu(void) 65 + { 66 + printf("[RUN]\tTesting getcpu...\n"); 67 + 68 + for (int cpu = 0; ; cpu++) { 69 + cpu_set_t cpuset; 70 + CPU_ZERO(&cpuset); 71 + CPU_SET(cpu, &cpuset); 72 + if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0) 73 + return; 74 + 75 + unsigned cpu_sys, cpu_vdso, cpu_vsys, 76 + node_sys, node_vdso, node_vsys; 77 + long ret_sys, ret_vdso = 1, ret_vsys = 1; 78 + unsigned node; 79 + 80 + ret_sys = sys_getcpu(&cpu_sys, &node_sys, 0); 81 + if (vdso_getcpu) 82 + ret_vdso = vdso_getcpu(&cpu_vdso, &node_vdso, 0); 83 + if (vgetcpu) 84 + ret_vsys = vgetcpu(&cpu_vsys, &node_vsys, 0); 85 + 86 + if (!ret_sys) 87 + node = node_sys; 88 + else if (!ret_vdso) 89 + node = node_vdso; 90 + else if (!ret_vsys) 91 + node = node_vsys; 92 + 93 + bool ok = true; 94 + if (!ret_sys && (cpu_sys != cpu || node_sys != node)) 95 + ok = false; 96 + if (!ret_vdso && (cpu_vdso != cpu || node_vdso != node)) 97 + ok = false; 98 + if (!ret_vsys && (cpu_vsys != cpu || node_vsys != node)) 99 + ok = false; 100 + 101 + printf("[%s]\tCPU %u:", ok ? "OK" : "FAIL", cpu); 102 + if (!ret_sys) 103 + printf(" syscall: cpu %u, node %u", cpu_sys, node_sys); 104 + if (!ret_vdso) 105 + printf(" vdso: cpu %u, node %u", cpu_vdso, node_vdso); 106 + if (!ret_vsys) 107 + printf(" vsyscall: cpu %u, node %u", cpu_vsys, 108 + node_vsys); 109 + printf("\n"); 110 + 111 + if (!ok) 112 + nerrs++; 113 + } 114 + } 115 + 116 + int main(int argc, char **argv) 117 + { 118 + fill_function_pointers(); 119 + 120 + test_getcpu(); 121 + 122 + return nerrs ? 1 : 0; 123 + }