Pull powerpc fixes from Michael Ellerman: "The headliner is a fix for FP/VMX register corruption when using transactional memory, and a new selftest to go with it. Then there's the virt_addr_valid() fix, currently HARDENDED_USERCOPY is tripping on that causing some machines to crash. A few other fairly minor fixes for long tail things, and a couple of fixes for code we just merged. Thanks to: Breno Leitao, Gautham Shenoy, Michael Neuling, Naveen Rao. Nicholas Piggin, Paul Mackerras" * tag 'powerpc-4.12-3' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux: powerpc/mm: Fix virt_addr_valid() etc. on 64-bit hash powerpc/mm: Fix crash in page table dump with huge pages powerpc/kprobes: Fix handling of instruction emulation on probe re-entry powerpc/powernv: Set NAPSTATELOST after recovering paca on P9 DD1 selftests/powerpc: Test TM and VMX register state powerpc/tm: Fix FP and VMX register corruption powerpc/modules: If mprofile-kernel is enabled add it to vermagic
Unified · Split
| @@ -14,6 +14,10 @@ · 13 unmodified lines | ||
| 14 | 14 | #include <asm-generic/module.h> |
| 15 | 15 | |
| 16 | 16 | |
| 17 | +#ifdef CC_USING_MPROFILE_KERNEL | |
| 18 | +#define MODULE_ARCH_VERMAGIC "mprofile-kernel" | |
| 19 | +#endif | |
| 20 | + | |
| 17 | 21 | #ifndef __powerpc64__ |
| 18 | 22 | /* |
| 19 | 23 | * Thanks to Paul M for explaining this. |
| @@ -132,7 +132,19 @@ extern long long virt_phys_offset; · 131 unmodified lines | ||
| 132 | 132 | #define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT) |
| 133 | 133 | #define virt_to_page(kaddr) pfn_to_page(virt_to_pfn(kaddr)) |
| 134 | 134 | #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) |
| 135 | + | |
| 136 | +#ifdef CONFIG_PPC_BOOK3S_64 | |
| 137 | +/* | |
| 138 | + * On hash the vmalloc and other regions alias to the kernel region when passed | |
| 139 | + * through __pa(), which virt_to_pfn() uses. That means virt_addr_valid() can | |
| 140 | + * return true for some vmalloc addresses, which is incorrect. So explicitly | |
| 141 | + * check that the address is in the kernel region. | |
| 142 | + */ | |
| 143 | +#define virt_addr_valid(kaddr) (REGION_ID(kaddr) == KERNEL_REGION_ID && \ | |
| 144 | + pfn_valid(virt_to_pfn(kaddr))) | |
| 145 | +#else | |
| 135 | 146 | #define virt_addr_valid(kaddr) pfn_valid(virt_to_pfn(kaddr)) |
| 147 | +#endif | |
| 136 | 148 | |
| 137 | 149 | /* |
| 138 | 150 | * On Book-E parts we need __va to parse the device tree and we can't |
| @@ -416,7 +416,7 @@ power9_dd1_recover_paca: · 415 unmodified lines | ||
| 416 | 416 | * which needs to be restored from the stack. |
| 417 | 417 | */ |
| 418 | 418 | li r3, 1 |
| 419 | − stb r0,PACA_NAPSTATELOST(r13) | |
| 419 | + stb r3,PACA_NAPSTATELOST(r13) | |
| 420 | 420 | blr |
| 421 | 421 | |
| 422 | 422 | /* |
| @@ -305,16 +305,17 @@ int kprobe_handler(struct pt_regs *regs) · 304 unmodified lines | ||
| 305 | 305 | save_previous_kprobe(kcb); |
| 306 | 306 | set_current_kprobe(p, regs, kcb); |
| 307 | 307 | kprobes_inc_nmissed_count(p); |
| 308 | − prepare_singlestep(p, regs); | |
| 309 | 308 | kcb->kprobe_status = KPROBE_REENTER; |
| 310 | 309 | if (p->ainsn.boostable >= 0) { |
| 311 | 310 | ret = try_to_emulate(p, regs); |
| 312 | 311 | |
| 313 | 312 | if (ret > 0) { |
| 314 | 313 | restore_previous_kprobe(kcb); |
| 314 | + preempt_enable_no_resched(); | |
| 315 | 315 | return 1; |
| 316 | 316 | } |
| 317 | 317 | } |
| 318 | + prepare_singlestep(p, regs); | |
| 318 | 319 | return 1; |
| 319 | 320 | } else { |
| 320 | 321 | if (*addr != BREAKPOINT_INSTRUCTION) { |
| @@ -864,6 +864,25 @@ static void tm_reclaim_thread(struct thread_struct *thr, · 863 unmodified lines | ||
| 864 | 864 | if (!MSR_TM_SUSPENDED(mfmsr())) |
| 865 | 865 | return; |
| 866 | 866 | |
| 867 | + /* | |
| 868 | + * If we are in a transaction and FP is off then we can't have | |
| 869 | + * used FP inside that transaction. Hence the checkpointed | |
| 870 | + * state is the same as the live state. We need to copy the | |
| 871 | + * live state to the checkpointed state so that when the | |
| 872 | + * transaction is restored, the checkpointed state is correct | |
| 873 | + * and the aborted transaction sees the correct state. We use | |
| 874 | + * ckpt_regs.msr here as that's what tm_reclaim will use to | |
| 875 | + * determine if it's going to write the checkpointed state or | |
| 876 | + * not. So either this will write the checkpointed registers, | |
| 877 | + * or reclaim will. Similarly for VMX. | |
| 878 | + */ | |
| 879 | + if ((thr->ckpt_regs.msr & MSR_FP) == 0) | |
| 880 | + memcpy(&thr->ckfp_state, &thr->fp_state, | |
| 881 | + sizeof(struct thread_fp_state)); | |
| 882 | + if ((thr->ckpt_regs.msr & MSR_VEC) == 0) | |
| 883 | + memcpy(&thr->ckvr_state, &thr->vr_state, | |
| 884 | + sizeof(struct thread_vr_state)); | |
| 885 | + | |
| 867 | 886 | giveup_all(container_of(thr, struct task_struct, thread)); |
| 868 | 887 | |
| 869 | 888 | tm_reclaim(thr, thr->ckpt_regs.msr, cause); |
| @@ -16,6 +16,7 @@ · 15 unmodified lines | ||
| 16 | 16 | */ |
| 17 | 17 | #include <linux/debugfs.h> |
| 18 | 18 | #include <linux/fs.h> |
| 19 | +#include <linux/hugetlb.h> | |
| 19 | 20 | #include <linux/io.h> |
| 20 | 21 | #include <linux/mm.h> |
| 21 | 22 | #include <linux/sched.h> |
| @@ -391,7 +392,7 @@ static void walk_pmd(struct pg_state *st, pud_t *pud, unsigned long start) · 369 unmodified lines | ||
| 391 | 392 | |
| 392 | 393 | for (i = 0; i < PTRS_PER_PMD; i++, pmd++) { |
| 393 | 394 | addr = start + i * PMD_SIZE; |
| 394 | − if (!pmd_none(*pmd)) | |
| 395 | + if (!pmd_none(*pmd) && !pmd_huge(*pmd)) | |
| 395 | 396 | /* pmd exists */ |
| 396 | 397 | walk_pte(st, pmd, addr); |
| 397 | 398 | else |
| @@ -407,7 +408,7 @@ static void walk_pud(struct pg_state *st, pgd_t *pgd, unsigned long start) · 9 unmodified lines | ||
| 407 | 408 | |
| 408 | 409 | for (i = 0; i < PTRS_PER_PUD; i++, pud++) { |
| 409 | 410 | addr = start + i * PUD_SIZE; |
| 410 | − if (!pud_none(*pud)) | |
| 411 | + if (!pud_none(*pud) && !pud_huge(*pud)) | |
| 411 | 412 | /* pud exists */ |
| 412 | 413 | walk_pmd(st, pud, addr); |
| 413 | 414 | else |
| @@ -427,7 +428,7 @@ static void walk_pagetables(struct pg_state *st) · 13 unmodified lines | ||
| 427 | 428 | */ |
| 428 | 429 | for (i = 0; i < PTRS_PER_PGD; i++, pgd++) { |
| 429 | 430 | addr = KERN_VIRT_START + i * PGDIR_SIZE; |
| 430 | − if (!pgd_none(*pgd)) | |
| 431 | + if (!pgd_none(*pgd) && !pgd_huge(*pgd)) | |
| 431 | 432 | /* pgd exists */ |
| 432 | 433 | walk_pud(st, pgd, addr); |
| 433 | 434 | else |
| @@ -11,3 +11,4 @@ tm-signal-context-chk-fpu · 10 unmodified lines | ||
| 11 | 11 | tm-signal-context-chk-gpr |
| 12 | 12 | tm-signal-context-chk-vmx |
| 13 | 13 | tm-signal-context-chk-vsx |
| 14 | +tm-vmx-unavail | |
| @@ -2,7 +2,8 @@ SIGNAL_CONTEXT_CHK_TESTS := tm-signal-context-chk-gpr tm-signal-context-chk-fpu · 1 unmodified line | ||
| 2 | 2 | tm-signal-context-chk-vmx tm-signal-context-chk-vsx |
| 3 | 3 | |
| 4 | 4 | TEST_GEN_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv tm-signal-stack \ |
| 5 | − tm-vmxcopy tm-fork tm-tar tm-tmspr $(SIGNAL_CONTEXT_CHK_TESTS) | |
| 5 | + tm-vmxcopy tm-fork tm-tar tm-tmspr tm-vmx-unavail \ | |
| 6 | + $(SIGNAL_CONTEXT_CHK_TESTS) | |
| 6 | 7 | |
| 7 | 8 | include ../../lib.mk |
| 8 | 9 | |
| @@ -13,6 +14,7 @@ CFLAGS += -mhtm · 4 unmodified lines | ||
| 13 | 14 | $(OUTPUT)/tm-syscall: tm-syscall-asm.S |
| 14 | 15 | $(OUTPUT)/tm-syscall: CFLAGS += -I../../../../../usr/include |
| 15 | 16 | $(OUTPUT)/tm-tmspr: CFLAGS += -pthread |
| 17 | +$(OUTPUT)/tm-vmx-unavail: CFLAGS += -pthread -m64 | |
| 16 | 18 | |
| 17 | 19 | SIGNAL_CONTEXT_CHK_TESTS := $(patsubst %,$(OUTPUT)/%,$(SIGNAL_CONTEXT_CHK_TESTS)) |
| 18 | 20 | $(SIGNAL_CONTEXT_CHK_TESTS): tm-signal.S |
| @@ -0,0 +1,118 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright 2017, Michael Neuling, IBM Corp. | |
| 3 | + * Licensed under GPLv2. | |
| 4 | + * Original: Breno Leitao <brenohl@br.ibm.com> & | |
| 5 | + * Gustavo Bueno Romero <gromero@br.ibm.com> | |
| 6 | + * Edited: Michael Neuling | |
| 7 | + * | |
| 8 | + * Force VMX unavailable during a transaction and see if it corrupts | |
| 9 | + * the checkpointed VMX register state after the abort. | |
| 10 | + */ | |
| 11 | + | |
| 12 | +#include <inttypes.h> | |
| 13 | +#include <htmintrin.h> | |
| 14 | +#include <string.h> | |
| 15 | +#include <stdlib.h> | |
| 16 | +#include <stdio.h> | |
| 17 | +#include <pthread.h> | |
| 18 | +#include <sys/mman.h> | |
| 19 | +#include <unistd.h> | |
| 20 | +#include <pthread.h> | |
| 21 | + | |
| 22 | +#include "tm.h" | |
| 23 | +#include "utils.h" | |
| 24 | + | |
| 25 | +int passed; | |
| 26 | + | |
| 27 | +void *worker(void *unused) | |
| 28 | +{ | |
| 29 | + __int128 vmx0; | |
| 30 | + uint64_t texasr; | |
| 31 | + | |
| 32 | + asm goto ( | |
| 33 | + "li 3, 1;" /* Stick non-zero value in VMX0 */ | |
| 34 | + "std 3, 0(%[vmx0_ptr]);" | |
| 35 | + "lvx 0, 0, %[vmx0_ptr];" | |
| 36 | + | |
| 37 | + /* Wait here a bit so we get scheduled out 255 times */ | |
| 38 | + "lis 3, 0x3fff;" | |
| 39 | + "1: ;" | |
| 40 | + "addi 3, 3, -1;" | |
| 41 | + "cmpdi 3, 0;" | |
| 42 | + "bne 1b;" | |
| 43 | + | |
| 44 | + /* Kernel will hopefully turn VMX off now */ | |
| 45 | + | |
| 46 | + "tbegin. ;" | |
| 47 | + "beq failure;" | |
| 48 | + | |
| 49 | + /* Cause VMX unavail. Any VMX instruction */ | |
| 50 | + "vaddcuw 0,0,0;" | |
| 51 | + | |
| 52 | + "tend. ;" | |
| 53 | + "b %l[success];" | |
| 54 | + | |
| 55 | + /* Check VMX0 sanity after abort */ | |
| 56 | + "failure: ;" | |
| 57 | + "lvx 1, 0, %[vmx0_ptr];" | |
| 58 | + "vcmpequb. 2, 0, 1;" | |
| 59 | + "bc 4, 24, %l[value_mismatch];" | |
| 60 | + "b %l[value_match];" | |
| 61 | + : | |
| 62 | + : [vmx0_ptr] "r"(&vmx0) | |
| 63 | + : "r3" | |
| 64 | + : success, value_match, value_mismatch | |
| 65 | + ); | |
| 66 | + | |
| 67 | + /* HTM aborted and VMX0 is corrupted */ | |
| 68 | +value_mismatch: | |
| 69 | + texasr = __builtin_get_texasr(); | |
| 70 | + | |
| 71 | + printf("\n\n==============\n\n"); | |
| 72 | + printf("Failure with error: %lx\n", _TEXASR_FAILURE_CODE(texasr)); | |
| 73 | + printf("Summary error : %lx\n", _TEXASR_FAILURE_SUMMARY(texasr)); | |
| 74 | + printf("TFIAR exact : %lx\n\n", _TEXASR_TFIAR_EXACT(texasr)); | |
| 75 | + | |
| 76 | + passed = 0; | |
| 77 | + return NULL; | |
| 78 | + | |
| 79 | + /* HTM aborted but VMX0 is correct */ | |
| 80 | +value_match: | |
| 81 | +// printf("!"); | |
| 82 | + return NULL; | |
| 83 | + | |
| 84 | +success: | |
| 85 | +// printf("."); | |
| 86 | + return NULL; | |
| 87 | +} | |
| 88 | + | |
| 89 | +int tm_vmx_unavail_test() | |
| 90 | +{ | |
| 91 | + int threads; | |
| 92 | + pthread_t *thread; | |
| 93 | + | |
| 94 | + SKIP_IF(!have_htm()); | |
| 95 | + | |
| 96 | + passed = 1; | |
| 97 | + | |
| 98 | + threads = sysconf(_SC_NPROCESSORS_ONLN) * 4; | |
| 99 | + thread = malloc(sizeof(pthread_t)*threads); | |
| 100 | + if (!thread) | |
| 101 | + return EXIT_FAILURE; | |
| 102 | + | |
| 103 | + for (uint64_t i = 0; i < threads; i++) | |
| 104 | + pthread_create(&thread[i], NULL, &worker, NULL); | |
| 105 | + | |
| 106 | + for (uint64_t i = 0; i < threads; i++) | |
| 107 | + pthread_join(thread[i], NULL); | |
| 108 | + | |
| 109 | + free(thread); | |
| 110 | + | |
| 111 | + return passed ? EXIT_SUCCESS : EXIT_FAILURE; | |
| 112 | +} | |
| 113 | + | |
| 114 | + | |
| 115 | +int main(int argc, char **argv) | |
| 116 | +{ | |
| 117 | + return test_harness(tm_vmx_unavail_test, "tm_vmx_unavail_test"); | |
| 118 | +} | |