2 * mono-hwcap-arm.c: ARM hardware feature detection
5 * Alex Rønne Petersen (alexrp@xamarin.com)
6 * Elijah Taylor (elijahtaylor@google.com)
7 * Miguel de Icaza (miguel@xamarin.com)
8 * Neale Ferguson (Neale.Ferguson@SoftwareAG-usa.com)
9 * Paolo Molaro (lupus@xamarin.com)
10 * Rodrigo Kumpera (kumpera@gmail.com)
11 * Sebastien Pouliot (sebastien@xamarin.com)
12 * Zoltan Varga (vargaz@xamarin.com)
14 * Copyright 2003 Ximian, Inc.
15 * Copyright 2003-2011 Novell, Inc
16 * Copyright 2006 Broadcom
17 * Copyright 2007-2008 Andreas Faerber
18 * Copyright 2011-2013 Xamarin Inc
19 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
22 #include "mono/utils/mono-hwcap-arm.h"
24 #if defined(HAVE_SYS_AUXV_H) && !defined(PLATFORM_ANDROID)
26 #elif defined(__APPLE__)
27 #include <mach/machine.h>
28 #include <sys/sysctl.h>
29 #include <sys/types.h>
31 #if defined (HAVE_SYS_UTSNAME_H)
32 #include <sys/utsname.h>
37 gboolean mono_hwcap_arm_is_v5 = FALSE;
38 gboolean mono_hwcap_arm_is_v6 = FALSE;
39 gboolean mono_hwcap_arm_is_v7 = FALSE;
40 gboolean mono_hwcap_arm_has_vfp = FALSE;
41 gboolean mono_hwcap_arm_has_vfp3 = FALSE;
42 gboolean mono_hwcap_arm_has_vfp3_d16 = FALSE;
43 gboolean mono_hwcap_arm_has_thumb = FALSE;
44 gboolean mono_hwcap_arm_has_thumb2 = FALSE;
47 mono_hwcap_arch_init (void)
49 #if defined(HAVE_SYS_AUXV_H) && !defined(PLATFORM_ANDROID)
51 unsigned long platform;
53 if ((hwcap = getauxval(AT_HWCAP))) {
55 if (hwcap & 0x00000004)
56 mono_hwcap_arm_has_thumb = TRUE;
59 if (hwcap & 0x00000040)
60 mono_hwcap_arm_has_vfp = TRUE;
63 if (hwcap & 0x00002000)
64 mono_hwcap_arm_has_vfp3 = TRUE;
66 /* HWCAP_ARM_VFPv3D16 */
67 if (hwcap & 0x00004000)
68 mono_hwcap_arm_has_vfp3_d16 = TRUE;
70 /* TODO: Find a way to detect Thumb 2. */
73 if ((platform = getauxval(AT_PLATFORM))) {
74 const char *str = (const char *) platform;
77 mono_hwcap_arm_is_v5 = TRUE;
80 mono_hwcap_arm_is_v6 = TRUE;
83 mono_hwcap_arm_is_v7 = TRUE;
85 /* TODO: Find a way to detect v7s. */
87 #elif defined(__APPLE__)
88 cpu_subtype_t sub_type;
89 size_t length = sizeof (sub_type);
91 sysctlbyname ("hw.cpusubtype", &sub_type, &length, NULL, 0);
93 if (sub_type == CPU_SUBTYPE_ARM_V5TEJ || sub_type == CPU_SUBTYPE_ARM_XSCALE) {
94 mono_hwcap_arm_is_v5 = TRUE;
95 } else if (sub_type == CPU_SUBTYPE_ARM_V6) {
96 mono_hwcap_arm_is_v5 = TRUE;
97 mono_hwcap_arm_is_v6 = TRUE;
98 } else if (sub_type == CPU_SUBTYPE_ARM_V7 || sub_type == CPU_SUBTYPE_ARM_V7F || sub_type == CPU_SUBTYPE_ARM_V7K) {
99 mono_hwcap_arm_is_v5 = TRUE;
100 mono_hwcap_arm_is_v6 = TRUE;
101 mono_hwcap_arm_is_v7 = TRUE;
104 /* TODO: Find a way to detect features like Thumb and VFP. */
106 /* We can't use the auxiliary vector on Android due to
107 * permissions, so fall back to /proc/cpuinfo. We also
108 * hit this path if the target doesn't have sys/auxv.h.
111 #if defined (HAVE_SYS_UTSNAME_H)
114 /* Only fails if `name` is invalid (it isn't). */
115 g_assert (!uname (&name));
117 if (!strncmp (name.machine, "aarch64", 7) || !strncmp (name.machine, "armv8", 5)) {
119 * We're a 32-bit program running on an ARMv8 system.
120 * Whether the system is actually 32-bit or 64-bit
121 * doesn't matter to us. The important thing is that
122 * all 3 of ARMv8's execution states (A64, A32, T32)
123 * are guaranteed to have all of the features that
124 * we want to detect and use.
126 * We do this ARMv8 detection via uname () because
127 * in the early days of ARMv8 on Linux, the
128 * /proc/cpuinfo format was a disaster and there
129 * were multiple (merged into mainline) attempts at
130 * cleaning it up (read: breaking applications that
131 * tried to rely on it). So now multiple ARMv8
132 * systems in the wild have different /proc/cpuinfo
133 * output, some of which are downright useless.
135 * So, when it comes to detecting ARMv8 in a 32-bit
136 * program, it's better to just avoid /proc/cpuinfo
137 * entirely. Maybe in a decade or two, we won't
138 * have to worry about this mess that the Linux ARM
139 * maintainers created. One can hope.
142 mono_hwcap_arm_is_v5 = TRUE;
143 mono_hwcap_arm_is_v6 = TRUE;
144 mono_hwcap_arm_is_v7 = TRUE;
146 mono_hwcap_arm_has_vfp = TRUE;
147 mono_hwcap_arm_has_vfp3 = TRUE;
148 mono_hwcap_arm_has_vfp3_d16 = TRUE;
150 mono_hwcap_arm_has_thumb = TRUE;
151 mono_hwcap_arm_has_thumb2 = TRUE;
158 FILE *file = fopen ("/proc/cpuinfo", "r");
161 while ((line = fgets (buf, 512, file))) {
162 if (!strncmp (line, "Processor", 9)) {
163 char *ver = strstr (line, "(v");
167 mono_hwcap_arm_is_v5 = TRUE;
170 mono_hwcap_arm_is_v6 = TRUE;
173 mono_hwcap_arm_is_v7 = TRUE;
175 /* TODO: Find a way to detect v7s. */
181 if (!strncmp (line, "Features", 8)) {
182 if (strstr (line, "thumb"))
183 mono_hwcap_arm_has_thumb = TRUE;
185 /* TODO: Find a way to detect Thumb 2. */
187 if (strstr (line, "vfp"))
188 mono_hwcap_arm_has_vfp = TRUE;
190 if (strstr (line, "vfpv3"))
191 mono_hwcap_arm_has_vfp3 = TRUE;
193 if (strstr (line, "vfpv3-d16"))
194 mono_hwcap_arm_has_vfp3_d16 = TRUE;
206 mono_hwcap_print(FILE *f)
208 g_fprintf (f, "mono_hwcap_arm_is_v5 = %i\n", mono_hwcap_arm_is_v5);
209 g_fprintf (f, "mono_hwcap_arm_is_v6 = %i\n", mono_hwcap_arm_is_v6);
210 g_fprintf (f, "mono_hwcap_arm_is_v7 = %i\n", mono_hwcap_arm_is_v7);
211 g_fprintf (f, "mono_hwcap_arm_has_vfp = %i\n", mono_hwcap_arm_has_vfp);
212 g_fprintf (f, "mono_hwcap_arm_has_vfp3 = %i\n", mono_hwcap_arm_has_vfp3);
213 g_fprintf (f, "mono_hwcap_arm_has_vfp3_d16 = %i\n", mono_hwcap_arm_has_vfp3_d16);
214 g_fprintf (f, "mono_hwcap_arm_has_thumb = %i\n", mono_hwcap_arm_has_thumb);
215 g_fprintf (f, "mono_hwcap_arm_has_thumb2 = %i\n", mono_hwcap_arm_has_thumb2);