eal: abstract away the auxiliary vector
[dpdk.git] / lib / librte_eal / common / eal_common_cpuflags.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2014 Intel Corporation
3  */
4
5 #include <elf.h>
6 #include <fcntl.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <sys/stat.h>
10 #include <sys/types.h>
11 #include <unistd.h>
12
13 #if defined(__GLIBC__) && defined(__GLIBC_PREREQ)
14 #if __GLIBC_PREREQ(2, 16)
15 #include <sys/auxv.h>
16 #define HAS_AUXV 1
17 #endif
18 #endif
19
20 #include <rte_common.h>
21 #include <rte_cpuflags.h>
22
23 #ifndef HAS_AUXV
24 static unsigned long
25 getauxval(unsigned long type)
26 {
27         errno = ENOTSUP;
28         return 0;
29 }
30 #endif
31
32 #ifdef RTE_ARCH_64
33 typedef Elf64_auxv_t Internal_Elfx_auxv_t;
34 #else
35 typedef Elf32_auxv_t Internal_Elfx_auxv_t;
36 #endif
37
38
39 /**
40  * Provides a method for retrieving values from the auxiliary vector and
41  * possibly running a string comparison.
42  *
43  * @return Always returns a result.  When the result is 0, check errno
44  * to see if an error occurred during processing.
45  */
46 static unsigned long
47 _rte_cpu_getauxval(unsigned long type, const char *str)
48 {
49         unsigned long val;
50
51         errno = 0;
52         val = getauxval(type);
53
54         if (!val && (errno == ENOTSUP || errno == ENOENT)) {
55                 int auxv_fd = open("/proc/self/auxv", O_RDONLY);
56                 Internal_Elfx_auxv_t auxv;
57
58                 if (auxv_fd == -1)
59                         return 0;
60
61                 errno = ENOENT;
62                 while (read(auxv_fd, &auxv, sizeof(auxv)) == sizeof(auxv)) {
63                         if (auxv.a_type == type) {
64                                 errno = 0;
65                                 val = auxv.a_un.a_val;
66                                 if (str)
67                                         val = strcmp((const char *)val, str);
68                                 break;
69                         }
70                 }
71                 close(auxv_fd);
72         }
73
74         return val;
75 }
76
77 unsigned long
78 rte_cpu_getauxval(unsigned long type)
79 {
80         return _rte_cpu_getauxval(type, NULL);
81 }
82
83 int
84 rte_cpu_strcmp_auxval(unsigned long type, const char *str)
85 {
86         return _rte_cpu_getauxval(type, str);
87 }
88
89 /**
90  * Checks if the machine is adequate for running the binary. If it is not, the
91  * program exits with status 1.
92  */
93 void
94 rte_cpu_check_supported(void)
95 {
96         if (!rte_cpu_is_supported())
97                 exit(1);
98 }
99
100 int
101 rte_cpu_is_supported(void)
102 {
103         /* This is generated at compile-time by the build system */
104         static const enum rte_cpu_flag_t compile_time_flags[] = {
105                         RTE_COMPILE_TIME_CPUFLAGS
106         };
107         unsigned count = RTE_DIM(compile_time_flags), i;
108         int ret;
109
110         for (i = 0; i < count; i++) {
111                 ret = rte_cpu_get_flag_enabled(compile_time_flags[i]);
112
113                 if (ret < 0) {
114                         fprintf(stderr,
115                                 "ERROR: CPU feature flag lookup failed with error %d\n",
116                                 ret);
117                         return 0;
118                 }
119                 if (!ret) {
120                         fprintf(stderr,
121                                 "ERROR: This system does not support \"%s\".\n"
122                                 "Please check that RTE_MACHINE is set correctly.\n",
123                                 rte_cpu_get_flag_name(compile_time_flags[i]));
124                         return 0;
125                 }
126         }
127
128         return 1;
129 }