From b9a95e85bbc56f168f078885f414f305b4589c4b Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 1 May 2015 13:48:17 +0100 Subject: [PATCH 1/4] Revert "arm64: alternative: Allow immediate branch as alternative instruction" This reverts most of commit fef7f2b2010381c795ae43743ad31931cc58f5ad. It turns out that there are a couple of problems with the way we're fixing up branch instructions used as part of alternative instruction sequences: (1) If the branch target is also in the alternative sequence, we'll generate a branch into the .altinstructions section which actually gets freed. (2) The calls to aarch64_insn_{read,write} bring an awful lot more code into the patching path (e.g. taking locks, poking the fixmap, invalidating the TLB) which isn't actually needed for the early patching run under stop_machine, but makes the use of alternative sequences extremely fragile (as we can't patch code that could be used by the patching code). Given that no code actually requires alternative patching of immediate branches, let's remove this support for now and revisit it when we've got a user. We leave the updated size check, since we really do require the sequences to be the same length. Acked-by: Marc Zyngier Signed-off-by: Will Deacon --- arch/arm64/kernel/alternative.c | 53 +-------------------------------- 1 file changed, 1 insertion(+), 52 deletions(-) diff --git a/arch/arm64/kernel/alternative.c b/arch/arm64/kernel/alternative.c index 21033bba9390..28f8365edc4c 100644 --- a/arch/arm64/kernel/alternative.c +++ b/arch/arm64/kernel/alternative.c @@ -24,7 +24,6 @@ #include #include #include -#include #include extern struct alt_instr __alt_instructions[], __alt_instructions_end[]; @@ -34,48 +33,6 @@ struct alt_region { struct alt_instr *end; }; -/* - * Decode the imm field of a b/bl instruction, and return the byte - * offset as a signed value (so it can be used when computing a new - * branch target). - */ -static s32 get_branch_offset(u32 insn) -{ - s32 imm = aarch64_insn_decode_immediate(AARCH64_INSN_IMM_26, insn); - - /* sign-extend the immediate before turning it into a byte offset */ - return (imm << 6) >> 4; -} - -static u32 get_alt_insn(u8 *insnptr, u8 *altinsnptr) -{ - u32 insn; - - aarch64_insn_read(altinsnptr, &insn); - - /* Stop the world on instructions we don't support... */ - BUG_ON(aarch64_insn_is_cbz(insn)); - BUG_ON(aarch64_insn_is_cbnz(insn)); - BUG_ON(aarch64_insn_is_bcond(insn)); - /* ... and there is probably more. */ - - if (aarch64_insn_is_b(insn) || aarch64_insn_is_bl(insn)) { - enum aarch64_insn_branch_type type; - unsigned long target; - - if (aarch64_insn_is_b(insn)) - type = AARCH64_INSN_BRANCH_NOLINK; - else - type = AARCH64_INSN_BRANCH_LINK; - - target = (unsigned long)altinsnptr + get_branch_offset(insn); - insn = aarch64_insn_gen_branch_imm((unsigned long)insnptr, - target, type); - } - - return insn; -} - static int __apply_alternatives(void *alt_region) { struct alt_instr *alt; @@ -83,9 +40,6 @@ static int __apply_alternatives(void *alt_region) u8 *origptr, *replptr; for (alt = region->begin; alt < region->end; alt++) { - u32 insn; - int i; - if (!cpus_have_cap(alt->cpufeature)) continue; @@ -95,12 +49,7 @@ static int __apply_alternatives(void *alt_region) origptr = (u8 *)&alt->orig_offset + alt->orig_offset; replptr = (u8 *)&alt->alt_offset + alt->alt_offset; - - for (i = 0; i < alt->alt_len; i += sizeof(insn)) { - insn = get_alt_insn(origptr + i, replptr + i); - aarch64_insn_write(origptr + i, insn); - } - + memcpy(origptr, replptr, alt->alt_len); flush_icache_range((uintptr_t)origptr, (uintptr_t)(origptr + alt->alt_len)); } From 326a780317d572711f70d53054502e86a1ff5317 Mon Sep 17 00:00:00 2001 From: Jungseung Lee Date: Mon, 4 May 2015 11:33:48 +0100 Subject: [PATCH 2/4] arm64: mm: Fix build error with CONFIG_SPARSEMEM_VMEMMAP disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fix the below build error: arch/arm64/mm/dump.c: In function ‘ptdump_init’: arch/arm64/mm/dump.c:331:18: error: ‘VMEMMAP_START_NR’ undeclared (first use in this function) address_markers[VMEMMAP_START_NR].start_address = ^ arch/arm64/mm/dump.c:331:18: note: each undeclared identifier is reported only once for each function it appears in arch/arm64/mm/dump.c:333:18: error: ‘VMEMMAP_END_NR’ undeclared (first use in this function) address_markers[VMEMMAP_END_NR].start_address = ^ Acked-by: Laura Abbott Signed-off-by: Jungseung Lee Signed-off-by: Will Deacon --- arch/arm64/mm/dump.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/mm/dump.c b/arch/arm64/mm/dump.c index 74c256744b25..f3d6221cd5bd 100644 --- a/arch/arm64/mm/dump.c +++ b/arch/arm64/mm/dump.c @@ -328,10 +328,12 @@ static int ptdump_init(void) for (j = 0; j < pg_level[i].num; j++) pg_level[i].mask |= pg_level[i].bits[j].mask; +#ifdef CONFIG_SPARSEMEM_VMEMMAP address_markers[VMEMMAP_START_NR].start_address = (unsigned long)virt_to_page(PAGE_OFFSET); address_markers[VMEMMAP_END_NR].start_address = (unsigned long)virt_to_page(high_memory); +#endif pe = debugfs_create_file("kernel_page_tables", 0400, NULL, NULL, &ptdump_fops); From 1e4df6b7208140f3c49f316d33a409d3a161f350 Mon Sep 17 00:00:00 2001 From: Xi Wang Date: Fri, 8 May 2015 06:39:51 +0100 Subject: [PATCH 3/4] arm64: bpf: fix signedness bug in loading 64-bit immediate Consider "(u64)insn1.imm << 32 | imm" in the arm64 JIT. Since imm is signed 32-bit, it is sign-extended to 64-bit, losing the high 32 bits. The fix is to convert imm to u32 first, which will be zero-extended to u64 implicitly. Cc: Zi Shen Lim Cc: Alexei Starovoitov Cc: Catalin Marinas Cc: Fixes: 30d3d94cc3d5 ("arm64: bpf: add 'load 64-bit immediate' instruction") Signed-off-by: Xi Wang [will: removed non-arm64 bits and redundant casting] Signed-off-by: Will Deacon --- arch/arm64/net/bpf_jit_comp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c index edba042b2325..dc6a4842683a 100644 --- a/arch/arm64/net/bpf_jit_comp.c +++ b/arch/arm64/net/bpf_jit_comp.c @@ -487,7 +487,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) return -EINVAL; } - imm64 = (u64)insn1.imm << 32 | imm; + imm64 = (u64)insn1.imm << 32 | (u32)imm; emit_a64_mov_i64(dst, imm64, ctx); return 1; From 4801ba338acad2e69e905e0c537e8ba2682c4e65 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 1 May 2015 17:15:23 +0100 Subject: [PATCH 4/4] arm64: perf: fix memory leak when probing PMU PPIs Commit d795ef9aa831 ("arm64: perf: don't warn about missing interrupt-affinity property for PPIs") added a check for PPIs so that we avoid parsing the interrupt-affinity property for these naturally affine interrupts. Unfortunately, this check can trigger an early (successful) return and we will leak the irqs array. This patch fixes the issue by reordering the code so that the check is performed before any independent allocation. Reported-by: David Binderman Signed-off-by: Will Deacon --- arch/arm64/kernel/perf_event.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c index 23f25acf43a9..cce18c85d2e8 100644 --- a/arch/arm64/kernel/perf_event.c +++ b/arch/arm64/kernel/perf_event.c @@ -1315,15 +1315,15 @@ static int armpmu_device_probe(struct platform_device *pdev) if (!cpu_pmu) return -ENODEV; - irqs = kcalloc(pdev->num_resources, sizeof(*irqs), GFP_KERNEL); - if (!irqs) - return -ENOMEM; - /* Don't bother with PPIs; they're already affine */ irq = platform_get_irq(pdev, 0); if (irq >= 0 && irq_is_percpu(irq)) return 0; + irqs = kcalloc(pdev->num_resources, sizeof(*irqs), GFP_KERNEL); + if (!irqs) + return -ENOMEM; + for (i = 0; i < pdev->num_resources; ++i) { struct device_node *dn; int cpu;