diff options
author | Suzuki K. Poulose <suzuki.poulose@arm.com> | 2015-10-19 09:24:46 -0400 |
---|---|---|
committer | Catalin Marinas <catalin.marinas@arm.com> | 2015-10-21 10:35:56 -0400 |
commit | 3086d391f992984def0aa6aa4a36f54853c58536 (patch) | |
tree | d83a9c5f47cce6fb234e1a46b09e0e381b74c6f9 | |
parent | 3c739b57108436211c7f798ba3de0bb0cd8ef469 (diff) |
arm64: Consolidate CPU Sanity check to CPU Feature infrastructure
This patch consolidates the CPU Sanity check to the new infrastructure.
Cc: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>
Tested-by: Dave Martin <Dave.Martin@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
-rw-r--r-- | arch/arm64/include/asm/cpu.h | 3 | ||||
-rw-r--r-- | arch/arm64/kernel/cpufeature.c | 164 | ||||
-rw-r--r-- | arch/arm64/kernel/cpuinfo.c | 113 |
3 files changed, 134 insertions, 146 deletions
diff --git a/arch/arm64/include/asm/cpu.h b/arch/arm64/include/asm/cpu.h index 704c17ba3ab0..b5e9cee4b5f8 100644 --- a/arch/arm64/include/asm/cpu.h +++ b/arch/arm64/include/asm/cpu.h | |||
@@ -64,6 +64,7 @@ void cpuinfo_store_cpu(void); | |||
64 | void __init cpuinfo_store_boot_cpu(void); | 64 | void __init cpuinfo_store_boot_cpu(void); |
65 | 65 | ||
66 | void __init init_cpu_features(struct cpuinfo_arm64 *info); | 66 | void __init init_cpu_features(struct cpuinfo_arm64 *info); |
67 | void update_cpu_features(struct cpuinfo_arm64 *info); | 67 | void update_cpu_features(int cpu, struct cpuinfo_arm64 *info, |
68 | struct cpuinfo_arm64 *boot); | ||
68 | 69 | ||
69 | #endif /* __ASM_CPU_H */ | 70 | #endif /* __ASM_CPU_H */ |
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 8d7abaa3a7f9..aae181760e1f 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c | |||
@@ -438,12 +438,9 @@ void __init init_cpu_features(struct cpuinfo_arm64 *info) | |||
438 | update_mixed_endian_el0_support(info); | 438 | update_mixed_endian_el0_support(info); |
439 | } | 439 | } |
440 | 440 | ||
441 | static void update_cpu_ftr_reg(u32 sys_reg, u64 new) | 441 | static void update_cpu_ftr_reg(struct arm64_ftr_reg *reg, u64 new) |
442 | { | 442 | { |
443 | struct arm64_ftr_bits *ftrp; | 443 | struct arm64_ftr_bits *ftrp; |
444 | struct arm64_ftr_reg *reg = get_arm64_ftr_reg(sys_reg); | ||
445 | |||
446 | BUG_ON(!reg); | ||
447 | 444 | ||
448 | for (ftrp = reg->ftr_bits; ftrp->width; ftrp++) { | 445 | for (ftrp = reg->ftr_bits; ftrp->width; ftrp++) { |
449 | s64 ftr_cur = arm64_ftr_value(ftrp, reg->sys_val); | 446 | s64 ftr_cur = arm64_ftr_value(ftrp, reg->sys_val); |
@@ -458,36 +455,137 @@ static void update_cpu_ftr_reg(u32 sys_reg, u64 new) | |||
458 | 455 | ||
459 | } | 456 | } |
460 | 457 | ||
461 | /* Update CPU feature register from non-boot CPU */ | 458 | static int check_update_ftr_reg(u32 sys_id, int cpu, u64 val, u64 boot) |
462 | void update_cpu_features(struct cpuinfo_arm64 *info) | ||
463 | { | 459 | { |
464 | update_cpu_ftr_reg(SYS_CTR_EL0, info->reg_ctr); | 460 | struct arm64_ftr_reg *regp = get_arm64_ftr_reg(sys_id); |
465 | update_cpu_ftr_reg(SYS_DCZID_EL0, info->reg_dczid); | 461 | |
466 | update_cpu_ftr_reg(SYS_CNTFRQ_EL0, info->reg_cntfrq); | 462 | BUG_ON(!regp); |
467 | update_cpu_ftr_reg(SYS_ID_AA64DFR0_EL1, info->reg_id_aa64dfr0); | 463 | update_cpu_ftr_reg(regp, val); |
468 | update_cpu_ftr_reg(SYS_ID_AA64DFR1_EL1, info->reg_id_aa64dfr1); | 464 | if ((boot & regp->strict_mask) == (val & regp->strict_mask)) |
469 | update_cpu_ftr_reg(SYS_ID_AA64ISAR0_EL1, info->reg_id_aa64isar0); | 465 | return 0; |
470 | update_cpu_ftr_reg(SYS_ID_AA64ISAR1_EL1, info->reg_id_aa64isar1); | 466 | pr_warn("SANITY CHECK: Unexpected variation in %s. Boot CPU: %#016llx, CPU%d: %#016llx\n", |
471 | update_cpu_ftr_reg(SYS_ID_AA64MMFR0_EL1, info->reg_id_aa64mmfr0); | 467 | regp->name, boot, cpu, val); |
472 | update_cpu_ftr_reg(SYS_ID_AA64MMFR1_EL1, info->reg_id_aa64mmfr1); | 468 | return 1; |
473 | update_cpu_ftr_reg(SYS_ID_AA64PFR0_EL1, info->reg_id_aa64pfr0); | 469 | } |
474 | update_cpu_ftr_reg(SYS_ID_AA64PFR1_EL1, info->reg_id_aa64pfr1); | 470 | |
475 | update_cpu_ftr_reg(SYS_ID_DFR0_EL1, info->reg_id_dfr0); | 471 | /* |
476 | update_cpu_ftr_reg(SYS_ID_ISAR0_EL1, info->reg_id_isar0); | 472 | * Update system wide CPU feature registers with the values from a |
477 | update_cpu_ftr_reg(SYS_ID_ISAR1_EL1, info->reg_id_isar1); | 473 | * non-boot CPU. Also performs SANITY checks to make sure that there |
478 | update_cpu_ftr_reg(SYS_ID_ISAR2_EL1, info->reg_id_isar2); | 474 | * aren't any insane variations from that of the boot CPU. |
479 | update_cpu_ftr_reg(SYS_ID_ISAR3_EL1, info->reg_id_isar3); | 475 | */ |
480 | update_cpu_ftr_reg(SYS_ID_ISAR4_EL1, info->reg_id_isar4); | 476 | void update_cpu_features(int cpu, |
481 | update_cpu_ftr_reg(SYS_ID_ISAR5_EL1, info->reg_id_isar5); | 477 | struct cpuinfo_arm64 *info, |
482 | update_cpu_ftr_reg(SYS_ID_MMFR0_EL1, info->reg_id_mmfr0); | 478 | struct cpuinfo_arm64 *boot) |
483 | update_cpu_ftr_reg(SYS_ID_MMFR1_EL1, info->reg_id_mmfr1); | 479 | { |
484 | update_cpu_ftr_reg(SYS_ID_MMFR2_EL1, info->reg_id_mmfr2); | 480 | int taint = 0; |
485 | update_cpu_ftr_reg(SYS_ID_MMFR3_EL1, info->reg_id_mmfr3); | 481 | |
486 | update_cpu_ftr_reg(SYS_ID_PFR0_EL1, info->reg_id_pfr0); | 482 | /* |
487 | update_cpu_ftr_reg(SYS_ID_PFR1_EL1, info->reg_id_pfr1); | 483 | * The kernel can handle differing I-cache policies, but otherwise |
488 | update_cpu_ftr_reg(SYS_MVFR0_EL1, info->reg_mvfr0); | 484 | * caches should look identical. Userspace JITs will make use of |
489 | update_cpu_ftr_reg(SYS_MVFR1_EL1, info->reg_mvfr1); | 485 | * *minLine. |
490 | update_cpu_ftr_reg(SYS_MVFR2_EL1, info->reg_mvfr2); | 486 | */ |
487 | taint |= check_update_ftr_reg(SYS_CTR_EL0, cpu, | ||
488 | info->reg_ctr, boot->reg_ctr); | ||
489 | |||
490 | /* | ||
491 | * Userspace may perform DC ZVA instructions. Mismatched block sizes | ||
492 | * could result in too much or too little memory being zeroed if a | ||
493 | * process is preempted and migrated between CPUs. | ||
494 | */ | ||
495 | taint |= check_update_ftr_reg(SYS_DCZID_EL0, cpu, | ||
496 | info->reg_dczid, boot->reg_dczid); | ||
497 | |||
498 | /* If different, timekeeping will be broken (especially with KVM) */ | ||
499 | taint |= check_update_ftr_reg(SYS_CNTFRQ_EL0, cpu, | ||
500 | info->reg_cntfrq, boot->reg_cntfrq); | ||
501 | |||
502 | /* | ||
503 | * The kernel uses self-hosted debug features and expects CPUs to | ||
504 | * support identical debug features. We presently need CTX_CMPs, WRPs, | ||
505 | * and BRPs to be identical. | ||
506 | * ID_AA64DFR1 is currently RES0. | ||
507 | */ | ||
508 | taint |= check_update_ftr_reg(SYS_ID_AA64DFR0_EL1, cpu, | ||
509 | info->reg_id_aa64dfr0, boot->reg_id_aa64dfr0); | ||
510 | taint |= check_update_ftr_reg(SYS_ID_AA64DFR1_EL1, cpu, | ||
511 | info->reg_id_aa64dfr1, boot->reg_id_aa64dfr1); | ||
512 | /* | ||
513 | * Even in big.LITTLE, processors should be identical instruction-set | ||
514 | * wise. | ||
515 | */ | ||
516 | taint |= check_update_ftr_reg(SYS_ID_AA64ISAR0_EL1, cpu, | ||
517 | info->reg_id_aa64isar0, boot->reg_id_aa64isar0); | ||
518 | taint |= check_update_ftr_reg(SYS_ID_AA64ISAR1_EL1, cpu, | ||
519 | info->reg_id_aa64isar1, boot->reg_id_aa64isar1); | ||
520 | |||
521 | /* | ||
522 | * Differing PARange support is fine as long as all peripherals and | ||
523 | * memory are mapped within the minimum PARange of all CPUs. | ||
524 | * Linux should not care about secure memory. | ||
525 | */ | ||
526 | taint |= check_update_ftr_reg(SYS_ID_AA64MMFR0_EL1, cpu, | ||
527 | info->reg_id_aa64mmfr0, boot->reg_id_aa64mmfr0); | ||
528 | taint |= check_update_ftr_reg(SYS_ID_AA64MMFR1_EL1, cpu, | ||
529 | info->reg_id_aa64mmfr1, boot->reg_id_aa64mmfr1); | ||
530 | |||
531 | /* | ||
532 | * EL3 is not our concern. | ||
533 | * ID_AA64PFR1 is currently RES0. | ||
534 | */ | ||
535 | taint |= check_update_ftr_reg(SYS_ID_AA64PFR0_EL1, cpu, | ||
536 | info->reg_id_aa64pfr0, boot->reg_id_aa64pfr0); | ||
537 | taint |= check_update_ftr_reg(SYS_ID_AA64PFR1_EL1, cpu, | ||
538 | info->reg_id_aa64pfr1, boot->reg_id_aa64pfr1); | ||
539 | |||
540 | /* | ||
541 | * If we have AArch32, we care about 32-bit features for compat. These | ||
542 | * registers should be RES0 otherwise. | ||
543 | */ | ||
544 | taint |= check_update_ftr_reg(SYS_ID_DFR0_EL1, cpu, | ||
545 | info->reg_id_dfr0, boot->reg_id_dfr0); | ||
546 | taint |= check_update_ftr_reg(SYS_ID_ISAR0_EL1, cpu, | ||
547 | info->reg_id_isar0, boot->reg_id_isar0); | ||
548 | taint |= check_update_ftr_reg(SYS_ID_ISAR1_EL1, cpu, | ||
549 | info->reg_id_isar1, boot->reg_id_isar1); | ||
550 | taint |= check_update_ftr_reg(SYS_ID_ISAR2_EL1, cpu, | ||
551 | info->reg_id_isar2, boot->reg_id_isar2); | ||
552 | taint |= check_update_ftr_reg(SYS_ID_ISAR3_EL1, cpu, | ||
553 | info->reg_id_isar3, boot->reg_id_isar3); | ||
554 | taint |= check_update_ftr_reg(SYS_ID_ISAR4_EL1, cpu, | ||
555 | info->reg_id_isar4, boot->reg_id_isar4); | ||
556 | taint |= check_update_ftr_reg(SYS_ID_ISAR5_EL1, cpu, | ||
557 | info->reg_id_isar5, boot->reg_id_isar5); | ||
558 | |||
559 | /* | ||
560 | * Regardless of the value of the AuxReg field, the AIFSR, ADFSR, and | ||
561 | * ACTLR formats could differ across CPUs and therefore would have to | ||
562 | * be trapped for virtualization anyway. | ||
563 | */ | ||
564 | taint |= check_update_ftr_reg(SYS_ID_MMFR0_EL1, cpu, | ||
565 | info->reg_id_mmfr0, boot->reg_id_mmfr0); | ||
566 | taint |= check_update_ftr_reg(SYS_ID_MMFR1_EL1, cpu, | ||
567 | info->reg_id_mmfr1, boot->reg_id_mmfr1); | ||
568 | taint |= check_update_ftr_reg(SYS_ID_MMFR2_EL1, cpu, | ||
569 | info->reg_id_mmfr2, boot->reg_id_mmfr2); | ||
570 | taint |= check_update_ftr_reg(SYS_ID_MMFR3_EL1, cpu, | ||
571 | info->reg_id_mmfr3, boot->reg_id_mmfr3); | ||
572 | taint |= check_update_ftr_reg(SYS_ID_PFR0_EL1, cpu, | ||
573 | info->reg_id_pfr0, boot->reg_id_pfr0); | ||
574 | taint |= check_update_ftr_reg(SYS_ID_PFR1_EL1, cpu, | ||
575 | info->reg_id_pfr1, boot->reg_id_pfr1); | ||
576 | taint |= check_update_ftr_reg(SYS_MVFR0_EL1, cpu, | ||
577 | info->reg_mvfr0, boot->reg_mvfr0); | ||
578 | taint |= check_update_ftr_reg(SYS_MVFR1_EL1, cpu, | ||
579 | info->reg_mvfr1, boot->reg_mvfr1); | ||
580 | taint |= check_update_ftr_reg(SYS_MVFR2_EL1, cpu, | ||
581 | info->reg_mvfr2, boot->reg_mvfr2); | ||
582 | |||
583 | /* | ||
584 | * Mismatched CPU features are a recipe for disaster. Don't even | ||
585 | * pretend to support them. | ||
586 | */ | ||
587 | WARN_TAINT_ONCE(taint, TAINT_CPU_OUT_OF_SPEC, | ||
588 | "Unsupported CPU feature variation.\n"); | ||
491 | 589 | ||
492 | update_mixed_endian_el0_support(info); | 590 | update_mixed_endian_el0_support(info); |
493 | } | 591 | } |
diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c index 857aaf05a143..f25869ea2646 100644 --- a/arch/arm64/kernel/cpuinfo.c +++ b/arch/arm64/kernel/cpuinfo.c | |||
@@ -192,116 +192,6 @@ static void cpuinfo_detect_icache_policy(struct cpuinfo_arm64 *info) | |||
192 | pr_info("Detected %s I-cache on CPU%d\n", icache_policy_str[l1ip], cpu); | 192 | pr_info("Detected %s I-cache on CPU%d\n", icache_policy_str[l1ip], cpu); |
193 | } | 193 | } |
194 | 194 | ||
195 | static int check_reg_mask(char *name, u64 mask, u64 boot, u64 cur, int cpu) | ||
196 | { | ||
197 | if ((boot & mask) == (cur & mask)) | ||
198 | return 0; | ||
199 | |||
200 | pr_warn("SANITY CHECK: Unexpected variation in %s. Boot CPU: %#016lx, CPU%d: %#016lx\n", | ||
201 | name, (unsigned long)boot, cpu, (unsigned long)cur); | ||
202 | |||
203 | return 1; | ||
204 | } | ||
205 | |||
206 | #define CHECK_MASK(field, mask, boot, cur, cpu) \ | ||
207 | check_reg_mask(#field, mask, (boot)->reg_ ## field, (cur)->reg_ ## field, cpu) | ||
208 | |||
209 | #define CHECK(field, boot, cur, cpu) \ | ||
210 | CHECK_MASK(field, ~0ULL, boot, cur, cpu) | ||
211 | |||
212 | /* | ||
213 | * Verify that CPUs don't have unexpected differences that will cause problems. | ||
214 | */ | ||
215 | static void cpuinfo_sanity_check(struct cpuinfo_arm64 *cur) | ||
216 | { | ||
217 | unsigned int cpu = smp_processor_id(); | ||
218 | struct cpuinfo_arm64 *boot = &boot_cpu_data; | ||
219 | unsigned int diff = 0; | ||
220 | |||
221 | /* | ||
222 | * The kernel can handle differing I-cache policies, but otherwise | ||
223 | * caches should look identical. Userspace JITs will make use of | ||
224 | * *minLine. | ||
225 | */ | ||
226 | diff |= CHECK_MASK(ctr, 0xffff3fff, boot, cur, cpu); | ||
227 | |||
228 | /* | ||
229 | * Userspace may perform DC ZVA instructions. Mismatched block sizes | ||
230 | * could result in too much or too little memory being zeroed if a | ||
231 | * process is preempted and migrated between CPUs. | ||
232 | */ | ||
233 | diff |= CHECK(dczid, boot, cur, cpu); | ||
234 | |||
235 | /* If different, timekeeping will be broken (especially with KVM) */ | ||
236 | diff |= CHECK(cntfrq, boot, cur, cpu); | ||
237 | |||
238 | /* | ||
239 | * The kernel uses self-hosted debug features and expects CPUs to | ||
240 | * support identical debug features. We presently need CTX_CMPs, WRPs, | ||
241 | * and BRPs to be identical. | ||
242 | * ID_AA64DFR1 is currently RES0. | ||
243 | */ | ||
244 | diff |= CHECK(id_aa64dfr0, boot, cur, cpu); | ||
245 | diff |= CHECK(id_aa64dfr1, boot, cur, cpu); | ||
246 | |||
247 | /* | ||
248 | * Even in big.LITTLE, processors should be identical instruction-set | ||
249 | * wise. | ||
250 | */ | ||
251 | diff |= CHECK(id_aa64isar0, boot, cur, cpu); | ||
252 | diff |= CHECK(id_aa64isar1, boot, cur, cpu); | ||
253 | |||
254 | /* | ||
255 | * Differing PARange support is fine as long as all peripherals and | ||
256 | * memory are mapped within the minimum PARange of all CPUs. | ||
257 | * Linux should not care about secure memory. | ||
258 | * ID_AA64MMFR1 is currently RES0. | ||
259 | */ | ||
260 | diff |= CHECK_MASK(id_aa64mmfr0, 0xffffffffffff0ff0, boot, cur, cpu); | ||
261 | diff |= CHECK(id_aa64mmfr1, boot, cur, cpu); | ||
262 | |||
263 | /* | ||
264 | * EL3 is not our concern. | ||
265 | * ID_AA64PFR1 is currently RES0. | ||
266 | */ | ||
267 | diff |= CHECK_MASK(id_aa64pfr0, 0xffffffffffff0fff, boot, cur, cpu); | ||
268 | diff |= CHECK(id_aa64pfr1, boot, cur, cpu); | ||
269 | |||
270 | /* | ||
271 | * If we have AArch32, we care about 32-bit features for compat. These | ||
272 | * registers should be RES0 otherwise. | ||
273 | */ | ||
274 | diff |= CHECK(id_dfr0, boot, cur, cpu); | ||
275 | diff |= CHECK(id_isar0, boot, cur, cpu); | ||
276 | diff |= CHECK(id_isar1, boot, cur, cpu); | ||
277 | diff |= CHECK(id_isar2, boot, cur, cpu); | ||
278 | diff |= CHECK(id_isar3, boot, cur, cpu); | ||
279 | diff |= CHECK(id_isar4, boot, cur, cpu); | ||
280 | diff |= CHECK(id_isar5, boot, cur, cpu); | ||
281 | /* | ||
282 | * Regardless of the value of the AuxReg field, the AIFSR, ADFSR, and | ||
283 | * ACTLR formats could differ across CPUs and therefore would have to | ||
284 | * be trapped for virtualization anyway. | ||
285 | */ | ||
286 | diff |= CHECK_MASK(id_mmfr0, 0xff0fffff, boot, cur, cpu); | ||
287 | diff |= CHECK(id_mmfr1, boot, cur, cpu); | ||
288 | diff |= CHECK(id_mmfr2, boot, cur, cpu); | ||
289 | diff |= CHECK(id_mmfr3, boot, cur, cpu); | ||
290 | diff |= CHECK(id_pfr0, boot, cur, cpu); | ||
291 | diff |= CHECK(id_pfr1, boot, cur, cpu); | ||
292 | |||
293 | diff |= CHECK(mvfr0, boot, cur, cpu); | ||
294 | diff |= CHECK(mvfr1, boot, cur, cpu); | ||
295 | diff |= CHECK(mvfr2, boot, cur, cpu); | ||
296 | |||
297 | /* | ||
298 | * Mismatched CPU features are a recipe for disaster. Don't even | ||
299 | * pretend to support them. | ||
300 | */ | ||
301 | WARN_TAINT_ONCE(diff, TAINT_CPU_OUT_OF_SPEC, | ||
302 | "Unsupported CPU feature variation.\n"); | ||
303 | } | ||
304 | |||
305 | static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info) | 195 | static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info) |
306 | { | 196 | { |
307 | info->reg_cntfrq = arch_timer_get_cntfrq(); | 197 | info->reg_cntfrq = arch_timer_get_cntfrq(); |
@@ -346,8 +236,7 @@ void cpuinfo_store_cpu(void) | |||
346 | { | 236 | { |
347 | struct cpuinfo_arm64 *info = this_cpu_ptr(&cpu_data); | 237 | struct cpuinfo_arm64 *info = this_cpu_ptr(&cpu_data); |
348 | __cpuinfo_store_cpu(info); | 238 | __cpuinfo_store_cpu(info); |
349 | cpuinfo_sanity_check(info); | 239 | update_cpu_features(smp_processor_id(), info, &boot_cpu_data); |
350 | update_cpu_features(info); | ||
351 | } | 240 | } |
352 | 241 | ||
353 | void __init cpuinfo_store_boot_cpu(void) | 242 | void __init cpuinfo_store_boot_cpu(void) |