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