1 /*
2 * Copyright (c) 2000-2024 Apple Inc. All rights reserved.
3 */
4 /*
5 * Copyright (C) 1990, NeXT, Inc.
6 *
7 * File: next/kern_machdep.c
8 * Author: John Seamons
9 *
10 * Machine-specific kernel routines.
11 */
12
13 #include <sys/types.h>
14 #include <mach/machine.h>
15 #include <kern/cpu_number.h>
16 #include <libkern/libkern.h>
17 #include <machine/exec.h>
18 #include <pexpert/arm64/board_config.h>
19
20 int ml_grade_binary(cpu_type_t, cpu_subtype_t, cpu_subtype_t, bool);
21
22 #if __arm64__
23 static cpu_subtype_t cpu_subtype32(void);
24 #endif /* __arm64__ */
25
26 #if __arm64__
27 /*
28 * When an arm64 CPU is executing an arm32 binary, we need to map from the
29 * host's 64-bit subtype to the appropriate 32-bit subtype.
30 */
31 static cpu_subtype_t
cpu_subtype32()32 cpu_subtype32()
33 {
34 switch (cpu_subtype()) {
35 case CPU_SUBTYPE_ARM64_V8:
36 return CPU_SUBTYPE_ARM_V8;
37 default:
38 return 0;
39 }
40 }
41
42 static int
grade_arm64e_binary(cpu_subtype_t execfeatures)43 grade_arm64e_binary(cpu_subtype_t execfeatures)
44 {
45 #if XNU_TARGET_OS_IOS || XNU_TARGET_OS_XR
46 /*
47 * iOS 13 toolchains produced unversioned arm64e slices which are not
48 * ABI compatible with this release.
49 */
50 if ((execfeatures & CPU_SUBTYPE_PTRAUTH_ABI) == 0) {
51 return 0;
52 }
53 #endif /* XNU_TARGET_OS_IOS || XNU_TARGET_OS_XR */
54
55 /* The current ABI version is preferred over arm64 */
56 if (CPU_SUBTYPE_ARM64_PTR_AUTH_VERSION(execfeatures) <=
57 CPU_SUBTYPE_ARM64_PTR_AUTH_MAX_PREFERRED_VERSION) {
58 return 12;
59 }
60
61 /* Non-preferred future and older ABIs are allowed, but exec_mach_imgact may treat them like an arm64 slice */
62 return 11;
63 }
64 #endif /* __arm64__ */
65
66 /**********************************************************************
67 * Routine: ml_grade_binary()
68 *
69 * Function: Return a relative preference for exectypes and
70 * execsubtypes in fat executable files. The higher the
71 * grade, the higher the preference. A grade of 0 means
72 * not acceptable.
73 **********************************************************************/
74 int
ml_grade_binary(cpu_type_t exectype,cpu_subtype_t execsubtype,cpu_subtype_t execfeatures __unused,bool allow_simulator_binary __unused)75 ml_grade_binary(cpu_type_t exectype, cpu_subtype_t execsubtype, cpu_subtype_t execfeatures __unused, bool allow_simulator_binary __unused)
76 {
77 #if __arm64__
78 cpu_subtype_t hostsubtype =
79 (exectype & CPU_ARCH_ABI64) ? cpu_subtype() : cpu_subtype32();
80 #else
81 cpu_subtype_t hostsubtype = cpu_subtype();
82 #endif /* __arm64__ */
83
84 switch (exectype) {
85 #if __arm64__
86 case CPU_TYPE_ARM64:
87 switch (hostsubtype) {
88 case CPU_SUBTYPE_ARM64_V8:
89 switch (execsubtype) {
90 case CPU_SUBTYPE_ARM64_V8:
91 return 10;
92 case CPU_SUBTYPE_ARM64_ALL:
93 return 9;
94 }
95 break;
96
97 case CPU_SUBTYPE_ARM64E:
98 switch (execsubtype) {
99 case CPU_SUBTYPE_ARM64E:
100 return grade_arm64e_binary(execfeatures);
101 case CPU_SUBTYPE_ARM64_V8:
102 return 10;
103 case CPU_SUBTYPE_ARM64_ALL:
104 return 9;
105 }
106 } /* switch (hostsubtype) */
107 break;
108
109 #else /* __arm64__ */
110
111 case CPU_TYPE_ARM:
112 switch (hostsubtype) {
113 /*
114 * For 32-bit ARMv8, try the ARMv8 slice before falling back to Swift.
115 */
116 case CPU_SUBTYPE_ARM_V8:
117 switch (execsubtype) {
118 case CPU_SUBTYPE_ARM_V8:
119 return 7;
120 }
121 goto v7s;
122
123 /*
124 * For Swift and later, we prefer to run a swift slice, but fall back
125 * to v7 as Cortex A9 errata should not apply
126 */
127 v7s:
128 case CPU_SUBTYPE_ARM_V7S:
129 switch (execsubtype) {
130 case CPU_SUBTYPE_ARM_V7S:
131 return 6;
132 }
133 goto v7;
134
135 /*
136 * For Cortex A7, accept v7k only due to differing ABI
137 */
138 case CPU_SUBTYPE_ARM_V7K:
139 switch (execsubtype) {
140 case CPU_SUBTYPE_ARM_V7K:
141 return 6;
142 }
143 break;
144
145 /*
146 * For Cortex A9, we prefer the A9 slice, but will run v7 albeit
147 * under the risk of hitting the NEON load/store errata
148 */
149 case CPU_SUBTYPE_ARM_V7F:
150 switch (execsubtype) {
151 case CPU_SUBTYPE_ARM_V7F:
152 return 6;
153 }
154 goto v7;
155
156 v7:
157 case CPU_SUBTYPE_ARM_V7:
158 switch (execsubtype) {
159 case CPU_SUBTYPE_ARM_V7:
160 return 5;
161 }
162 // fall through...
163
164 case CPU_SUBTYPE_ARM_V6:
165 switch (execsubtype) {
166 case CPU_SUBTYPE_ARM_V6:
167 return 4;
168 }
169 // fall through...
170
171 case CPU_SUBTYPE_ARM_V5TEJ:
172 switch (execsubtype) {
173 case CPU_SUBTYPE_ARM_V5TEJ:
174 return 3;
175 }
176 // fall through
177
178 case CPU_SUBTYPE_ARM_V4T:
179 switch (execsubtype) {
180 case CPU_SUBTYPE_ARM_V4T:
181 return 2;
182 case CPU_SUBTYPE_ARM_ALL:
183 return 1;
184 }
185 break;
186
187 case CPU_SUBTYPE_ARM_XSCALE:
188 switch (execsubtype) {
189 case CPU_SUBTYPE_ARM_XSCALE:
190 return 4;
191 case CPU_SUBTYPE_ARM_V5TEJ:
192 return 3;
193 case CPU_SUBTYPE_ARM_V4T:
194 return 2;
195 case CPU_SUBTYPE_ARM_ALL:
196 return 1;
197 }
198 break;
199 }
200 #endif /* __arm64__ */
201 }
202
203 return 0;
204 }
205