xref: /xnu-12377.61.12/bsd/dev/arm/kern_machdep.c (revision 4d495c6e23c53686cf65f45067f79024cf5dcee8)
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