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