[runtime] Use HOST_ defines instead of PLATFORM_ defines. (#5362)
[mono.git] / mono / utils / mono-hwcap-arm.c
1 /**
2  * \file
3  * ARM hardware feature detection
4  *
5  * Authors:
6  *    Alex Rønne Petersen (alexrp@xamarin.com)
7  *    Elijah Taylor (elijahtaylor@google.com)
8  *    Miguel de Icaza (miguel@xamarin.com)
9  *    Neale Ferguson (Neale.Ferguson@SoftwareAG-usa.com)
10  *    Paolo Molaro (lupus@xamarin.com)
11  *    Rodrigo Kumpera (kumpera@gmail.com)
12  *    Sebastien Pouliot (sebastien@xamarin.com)
13  *    Zoltan Varga (vargaz@xamarin.com)
14  *
15  * Copyright 2003 Ximian, Inc.
16  * Copyright 2003-2011 Novell, Inc
17  * Copyright 2006 Broadcom
18  * Copyright 2007-2008 Andreas Faerber
19  * Copyright 2011-2013 Xamarin Inc
20  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
21  */
22
23 #include "mono/utils/mono-hwcap.h"
24
25 #if defined(HAVE_SYS_AUXV_H) && !defined(HOST_ANDROID)
26 #include <sys/auxv.h>
27 #elif defined(__APPLE__)
28 #include <mach/machine.h>
29 #include <sys/sysctl.h>
30 #include <sys/types.h>
31 #else
32 #if defined (HAVE_SYS_UTSNAME_H)
33 #include <sys/utsname.h>
34 #endif
35 #include <stdio.h>
36 #endif
37
38 void
39 mono_hwcap_arch_init (void)
40 {
41 #if defined(HAVE_SYS_AUXV_H) && !defined(HOST_ANDROID)
42         unsigned long hwcap;
43         unsigned long platform;
44
45         if ((hwcap = getauxval(AT_HWCAP))) {
46                 /* HWCAP_ARM_THUMB */
47                 if (hwcap & 0x00000004)
48                         mono_hwcap_arm_has_thumb = TRUE;
49
50                 /* HWCAP_ARM_VFP */
51                 if (hwcap & 0x00000040)
52                         mono_hwcap_arm_has_vfp = TRUE;
53
54                 /* HWCAP_ARM_VFPv3 */
55                 if (hwcap & 0x00002000)
56                         mono_hwcap_arm_has_vfp3 = TRUE;
57
58                 /* HWCAP_ARM_VFPv3D16 */
59                 if (hwcap & 0x00004000)
60                         mono_hwcap_arm_has_vfp3_d16 = TRUE;
61
62                 /* TODO: Find a way to detect Thumb 2. */
63         }
64
65         if ((platform = getauxval(AT_PLATFORM))) {
66                 const char *str = (const char *) platform;
67
68                 if (str [1] >= '5')
69                         mono_hwcap_arm_is_v5 = TRUE;
70
71                 if (str [1] >= '6')
72                         mono_hwcap_arm_is_v6 = TRUE;
73
74                 if (str [1] >= '7')
75                         mono_hwcap_arm_is_v7 = TRUE;
76
77                 /* TODO: Find a way to detect v7s. */
78         }
79 #elif defined(__APPLE__)
80         cpu_subtype_t sub_type;
81         size_t length = sizeof (sub_type);
82
83         sysctlbyname ("hw.cpusubtype", &sub_type, &length, NULL, 0);
84
85         if (sub_type == CPU_SUBTYPE_ARM_V5TEJ || sub_type == CPU_SUBTYPE_ARM_XSCALE) {
86                 mono_hwcap_arm_is_v5 = TRUE;
87         } else if (sub_type == CPU_SUBTYPE_ARM_V6) {
88                 mono_hwcap_arm_is_v5 = TRUE;
89                 mono_hwcap_arm_is_v6 = TRUE;
90         } else if (sub_type == CPU_SUBTYPE_ARM_V7 || sub_type == CPU_SUBTYPE_ARM_V7F || sub_type == CPU_SUBTYPE_ARM_V7K) {
91                 mono_hwcap_arm_is_v5 = TRUE;
92                 mono_hwcap_arm_is_v6 = TRUE;
93                 mono_hwcap_arm_is_v7 = TRUE;
94         }
95
96         /* TODO: Find a way to detect features like Thumb and VFP. */
97 #else
98         /* We can't use the auxiliary vector on Android due to
99          * permissions, so fall back to /proc/cpuinfo. We also
100          * hit this path if the target doesn't have sys/auxv.h.
101          */
102
103 #if defined (HAVE_SYS_UTSNAME_H)
104         struct utsname name;
105
106         /* Only fails if `name` is invalid (it isn't). */
107         g_assert (!uname (&name));
108
109         if (!strncmp (name.machine, "aarch64", 7) || !strncmp (name.machine, "armv8", 5)) {
110                 /*
111                  * We're a 32-bit program running on an ARMv8 system.
112                  * Whether the system is actually 32-bit or 64-bit
113                  * doesn't matter to us. The important thing is that
114                  * all 3 of ARMv8's execution states (A64, A32, T32)
115                  * are guaranteed to have all of the features that
116                  * we want to detect and use.
117                  *
118                  * We do this ARMv8 detection via uname () because
119                  * in the early days of ARMv8 on Linux, the
120                  * /proc/cpuinfo format was a disaster and there
121                  * were multiple (merged into mainline) attempts at
122                  * cleaning it up (read: breaking applications that
123                  * tried to rely on it). So now multiple ARMv8
124                  * systems in the wild have different /proc/cpuinfo
125                  * output, some of which are downright useless.
126                  *
127                  * So, when it comes to detecting ARMv8 in a 32-bit
128                  * program, it's better to just avoid /proc/cpuinfo
129                  * entirely. Maybe in a decade or two, we won't
130                  * have to worry about this mess that the Linux ARM
131                  * maintainers created. One can hope.
132                  */
133
134                 mono_hwcap_arm_is_v5 = TRUE;
135                 mono_hwcap_arm_is_v6 = TRUE;
136                 mono_hwcap_arm_is_v7 = TRUE;
137
138                 mono_hwcap_arm_has_vfp = TRUE;
139                 mono_hwcap_arm_has_vfp3 = TRUE;
140                 mono_hwcap_arm_has_vfp3_d16 = TRUE;
141
142                 mono_hwcap_arm_has_thumb = TRUE;
143                 mono_hwcap_arm_has_thumb2 = TRUE;
144         }
145 #endif
146
147         char buf [512];
148         char *line;
149
150         FILE *file = fopen ("/proc/cpuinfo", "r");
151
152         if (file) {
153                 while ((line = fgets (buf, 512, file))) {
154                         if (!strncmp (line, "Processor", 9) ||
155                             !strncmp (line, "model name", 10)) {
156                                 char *ver = strstr (line, "(v");
157
158                                 if (ver) {
159                                         if (ver [2] >= '5')
160                                                 mono_hwcap_arm_is_v5 = TRUE;
161
162                                         if (ver [2] >= '6')
163                                                 mono_hwcap_arm_is_v6 = TRUE;
164
165                                         if (ver [2] >= '7')
166                                                 mono_hwcap_arm_is_v7 = TRUE;
167
168                                         /* TODO: Find a way to detect v7s. */
169                                 }
170
171                                 continue;
172                         }
173
174                         if (!strncmp (line, "Features", 8)) {
175                                 if (strstr (line, "thumb"))
176                                         mono_hwcap_arm_has_thumb = TRUE;
177
178                                 /* TODO: Find a way to detect Thumb 2. */
179
180                                 if (strstr (line, "vfp"))
181                                         mono_hwcap_arm_has_vfp = TRUE;
182
183                                 if (strstr (line, "vfpv3"))
184                                         mono_hwcap_arm_has_vfp3 = TRUE;
185
186                                 if (strstr (line, "vfpv3-d16"))
187                                         mono_hwcap_arm_has_vfp3_d16 = TRUE;
188
189                                 continue;
190                         }
191                 }
192
193                 fclose (file);
194         }
195 #endif
196 }