|
29 | 29 | #include <asm/mmu_context.h>
|
30 | 30 | #include <asm/processor.h>
|
31 | 31 | #include <asm/sysreg.h>
|
| 32 | +#include <asm/traps.h> |
32 | 33 | #include <asm/virt.h>
|
33 | 34 |
|
34 | 35 | unsigned long elf_hwcap __read_mostly;
|
@@ -940,6 +941,8 @@ static bool cpus_have_elf_hwcap(const struct arm64_cpu_capabilities *cap)
|
940 | 941 |
|
941 | 942 | static void __init setup_elf_hwcaps(const struct arm64_cpu_capabilities *hwcaps)
|
942 | 943 | {
|
| 944 | + /* We support emulation of accesses to CPU ID feature registers */ |
| 945 | + elf_hwcap |= HWCAP_CPUID; |
943 | 946 | for (; hwcaps->matches; hwcaps++)
|
944 | 947 | if (hwcaps->matches(hwcaps, hwcaps->def_scope))
|
945 | 948 | cap_set_elf_hwcap(hwcaps);
|
@@ -1127,3 +1130,101 @@ cpufeature_pan_not_uao(const struct arm64_cpu_capabilities *entry, int __unused)
|
1127 | 1130 | {
|
1128 | 1131 | return (cpus_have_const_cap(ARM64_HAS_PAN) && !cpus_have_const_cap(ARM64_HAS_UAO));
|
1129 | 1132 | }
|
| 1133 | + |
| 1134 | +/* |
| 1135 | + * We emulate only the following system register space. |
| 1136 | + * Op0 = 0x3, CRn = 0x0, Op1 = 0x0, CRm = [0, 4 - 7] |
| 1137 | + * See Table C5-6 System instruction encodings for System register accesses, |
| 1138 | + * ARMv8 ARM(ARM DDI 0487A.f) for more details. |
| 1139 | + */ |
| 1140 | +static inline bool __attribute_const__ is_emulated(u32 id) |
| 1141 | +{ |
| 1142 | + return (sys_reg_Op0(id) == 0x3 && |
| 1143 | + sys_reg_CRn(id) == 0x0 && |
| 1144 | + sys_reg_Op1(id) == 0x0 && |
| 1145 | + (sys_reg_CRm(id) == 0 || |
| 1146 | + ((sys_reg_CRm(id) >= 4) && (sys_reg_CRm(id) <= 7)))); |
| 1147 | +} |
| 1148 | + |
| 1149 | +/* |
| 1150 | + * With CRm == 0, reg should be one of : |
| 1151 | + * MIDR_EL1, MPIDR_EL1 or REVIDR_EL1. |
| 1152 | + */ |
| 1153 | +static inline int emulate_id_reg(u32 id, u64 *valp) |
| 1154 | +{ |
| 1155 | + switch (id) { |
| 1156 | + case SYS_MIDR_EL1: |
| 1157 | + *valp = read_cpuid_id(); |
| 1158 | + break; |
| 1159 | + case SYS_MPIDR_EL1: |
| 1160 | + *valp = SYS_MPIDR_SAFE_VAL; |
| 1161 | + break; |
| 1162 | + case SYS_REVIDR_EL1: |
| 1163 | + /* IMPLEMENTATION DEFINED values are emulated with 0 */ |
| 1164 | + *valp = 0; |
| 1165 | + break; |
| 1166 | + default: |
| 1167 | + return -EINVAL; |
| 1168 | + } |
| 1169 | + |
| 1170 | + return 0; |
| 1171 | +} |
| 1172 | + |
| 1173 | +static int emulate_sys_reg(u32 id, u64 *valp) |
| 1174 | +{ |
| 1175 | + struct arm64_ftr_reg *regp; |
| 1176 | + |
| 1177 | + if (!is_emulated(id)) |
| 1178 | + return -EINVAL; |
| 1179 | + |
| 1180 | + if (sys_reg_CRm(id) == 0) |
| 1181 | + return emulate_id_reg(id, valp); |
| 1182 | + |
| 1183 | + regp = get_arm64_ftr_reg(id); |
| 1184 | + if (regp) |
| 1185 | + *valp = arm64_ftr_reg_user_value(regp); |
| 1186 | + else |
| 1187 | + /* |
| 1188 | + * The untracked registers are either IMPLEMENTATION DEFINED |
| 1189 | + * (e.g, ID_AFR0_EL1) or reserved RAZ. |
| 1190 | + */ |
| 1191 | + *valp = 0; |
| 1192 | + return 0; |
| 1193 | +} |
| 1194 | + |
| 1195 | +static int emulate_mrs(struct pt_regs *regs, u32 insn) |
| 1196 | +{ |
| 1197 | + int rc; |
| 1198 | + u32 sys_reg, dst; |
| 1199 | + u64 val; |
| 1200 | + |
| 1201 | + /* |
| 1202 | + * sys_reg values are defined as used in mrs/msr instruction. |
| 1203 | + * shift the imm value to get the encoding. |
| 1204 | + */ |
| 1205 | + sys_reg = (u32)aarch64_insn_decode_immediate(AARCH64_INSN_IMM_16, insn) << 5; |
| 1206 | + rc = emulate_sys_reg(sys_reg, &val); |
| 1207 | + if (!rc) { |
| 1208 | + dst = aarch64_insn_decode_register(AARCH64_INSN_REGTYPE_RT, insn); |
| 1209 | + regs->user_regs.regs[dst] = val; |
| 1210 | + regs->pc += 4; |
| 1211 | + } |
| 1212 | + |
| 1213 | + return rc; |
| 1214 | +} |
| 1215 | + |
| 1216 | +static struct undef_hook mrs_hook = { |
| 1217 | + .instr_mask = 0xfff00000, |
| 1218 | + .instr_val = 0xd5300000, |
| 1219 | + .pstate_mask = COMPAT_PSR_MODE_MASK, |
| 1220 | + .pstate_val = PSR_MODE_EL0t, |
| 1221 | + .fn = emulate_mrs, |
| 1222 | +}; |
| 1223 | + |
| 1224 | +static int __init enable_mrs_emulation(void) |
| 1225 | +{ |
| 1226 | + register_undef_hook(&mrs_hook); |
| 1227 | + return 0; |
| 1228 | +} |
| 1229 | + |
| 1230 | +late_initcall(enable_mrs_emulation); |
0 commit comments