| 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__ |
| 21 | static 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 | */ |
| 29 | static cpu_subtype_t |
| 30 | cpu_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 | |
| 40 | static int |
| 41 | grade_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 | **********************************************************************/ |
| 72 | int |
| 73 | grade_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 | */ |
| 125 | v7s: |
| 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 | |
| 154 | v7: |
| 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 | |