Merge pull request #3121 from lambdageek/dev/managed-init_message
[mono.git] / mono / utils / mono-hwcap-arm.c
1 /*
2  * mono-hwcap-arm.c: ARM hardware feature detection
3  *
4  * Authors:
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)
13  *
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.
20  */
21
22 #include "mono/utils/mono-hwcap-arm.h"
23
24 #if defined(HAVE_SYS_AUXV_H) && !defined(PLATFORM_ANDROID)
25 #include <sys/auxv.h>
26 #elif defined(__APPLE__)
27 #include <mach/machine.h>
28 #include <sys/sysctl.h>
29 #include <sys/types.h>
30 #else
31 #if defined (HAVE_SYS_UTSNAME_H)
32 #include <sys/utsname.h>
33 #endif
34 #include <stdio.h>
35 #endif
36
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;
45
46 void
47 mono_hwcap_arch_init (void)
48 {
49 #if defined(HAVE_SYS_AUXV_H) && !defined(PLATFORM_ANDROID)
50         unsigned long hwcap;
51         unsigned long platform;
52
53         if ((hwcap = getauxval(AT_HWCAP))) {
54                 /* HWCAP_ARM_THUMB */
55                 if (hwcap & 0x00000004)
56                         mono_hwcap_arm_has_thumb = TRUE;
57
58                 /* HWCAP_ARM_VFP */
59                 if (hwcap & 0x00000040)
60                         mono_hwcap_arm_has_vfp = TRUE;
61
62                 /* HWCAP_ARM_VFPv3 */
63                 if (hwcap & 0x00002000)
64                         mono_hwcap_arm_has_vfp3 = TRUE;
65
66                 /* HWCAP_ARM_VFPv3D16 */
67                 if (hwcap & 0x00004000)
68                         mono_hwcap_arm_has_vfp3_d16 = TRUE;
69
70                 /* TODO: Find a way to detect Thumb 2. */
71         }
72
73         if ((platform = getauxval(AT_PLATFORM))) {
74                 const char *str = (const char *) platform;
75
76                 if (str [1] >= '5')
77                         mono_hwcap_arm_is_v5 = TRUE;
78
79                 if (str [1] >= '6')
80                         mono_hwcap_arm_is_v6 = TRUE;
81
82                 if (str [1] >= '7')
83                         mono_hwcap_arm_is_v7 = TRUE;
84
85                 /* TODO: Find a way to detect v7s. */
86         }
87 #elif defined(__APPLE__)
88         cpu_subtype_t sub_type;
89         size_t length = sizeof (sub_type);
90
91         sysctlbyname ("hw.cpusubtype", &sub_type, &length, NULL, 0);
92
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;
102         }
103
104         /* TODO: Find a way to detect features like Thumb and VFP. */
105 #else
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.
109          */
110
111 #if defined (HAVE_SYS_UTSNAME_H)
112         struct utsname name;
113
114         /* Only fails if `name` is invalid (it isn't). */
115         g_assert (!uname (&name));
116
117         if (!strncmp (name.machine, "aarch64", 7) || !strncmp (name.machine, "armv8", 5)) {
118                 /*
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.
125                  *
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.
134                  *
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.
140                  */
141
142                 mono_hwcap_arm_is_v5 = TRUE;
143                 mono_hwcap_arm_is_v6 = TRUE;
144                 mono_hwcap_arm_is_v7 = TRUE;
145
146                 mono_hwcap_arm_has_vfp = TRUE;
147                 mono_hwcap_arm_has_vfp3 = TRUE;
148                 mono_hwcap_arm_has_vfp3_d16 = TRUE;
149
150                 mono_hwcap_arm_has_thumb = TRUE;
151                 mono_hwcap_arm_has_thumb2 = TRUE;
152         }
153 #endif
154
155         char buf [512];
156         char *line;
157
158         FILE *file = fopen ("/proc/cpuinfo", "r");
159
160         if (file) {
161                 while ((line = fgets (buf, 512, file))) {
162                         if (!strncmp (line, "Processor", 9)) {
163                                 char *ver = strstr (line, "(v");
164
165                                 if (ver) {
166                                         if (ver [2] >= '5')
167                                                 mono_hwcap_arm_is_v5 = TRUE;
168
169                                         if (ver [2] >= '6')
170                                                 mono_hwcap_arm_is_v6 = TRUE;
171
172                                         if (ver [2] >= '7')
173                                                 mono_hwcap_arm_is_v7 = TRUE;
174
175                                         /* TODO: Find a way to detect v7s. */
176                                 }
177
178                                 continue;
179                         }
180
181                         if (!strncmp (line, "Features", 8)) {
182                                 if (strstr (line, "thumb"))
183                                         mono_hwcap_arm_has_thumb = TRUE;
184
185                                 /* TODO: Find a way to detect Thumb 2. */
186
187                                 if (strstr (line, "vfp"))
188                                         mono_hwcap_arm_has_vfp = TRUE;
189
190                                 if (strstr (line, "vfpv3"))
191                                         mono_hwcap_arm_has_vfp3 = TRUE;
192
193                                 if (strstr (line, "vfpv3-d16"))
194                                         mono_hwcap_arm_has_vfp3_d16 = TRUE;
195
196                                 continue;
197                         }
198                 }
199
200                 fclose (file);
201         }
202 #endif
203 }
204
205 void
206 mono_hwcap_print(FILE *f)
207 {
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);
216 }