Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp1271995imu; Wed, 9 Jan 2019 15:02:45 -0800 (PST) X-Google-Smtp-Source: ALg8bN71x0QQr/7vEFkmEAu5r6bNN81KRJma0rL12MESm2xE7EEgRbmRy3E8gGX3BvAhybBu1/f4 X-Received: by 2002:a17:902:e002:: with SMTP id ca2mr8078001plb.103.1547074965829; Wed, 09 Jan 2019 15:02:45 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1547074965; cv=none; d=google.com; s=arc-20160816; b=xdpYNir+dFyTJQcbQ1prwi7fNhGUG+fBgkpALD/ydTLO9Hn69aoJGifGZBCL/dpe52 rcyZuEH/AFXxO38+98HMVExy/ZyN7/rSDywnYSj1ZI5m7NkwVZI+jLJ9Oh98bm2b3oSU e3YugcfnEQ3fO5LO68uvJKG98Oh4mKVWrvm4a2Z1Q2XRFdtMnA6b6CNn+49vmm8OkGyC vP0jI3zs7kxCTlEYT6lV8lCcH3KQba8kraKAzxIx4V1FX9sHvpB0LuefrPv1sX+N4muR LG0qA6AbBFHgMqKS3kythKhS6R3RIEpwAjoYgOBo2a+FkYJs616foIXcHYHis5ogbN9w j4HQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from; bh=W2ni1mwiQmu9RQPIscwUNsqOKnxDf7oH4ByCZidN7wY=; b=zVUxhKPPg610h3O4YGLMaQVtDauRqbEPZUO1EeLMCbADi1CK9KV/rWk902FCOmwexb nNiBEqB5oeqSCzYlAmFnJpV6yB0GweHedlD017fYsIPAaWPC3246DLoP2rjSv+yUL4vk 61ByONCF20RawBeTgaggqYo2qzYgJpgZ5vWP6sYB0A/NVMEcIFXkJ82lErKWyNHX9ClI gt46HMGNyio/tdcDbY+VfIh22au8Ql+t45BzT7V/IBsi+kNAj9rurNmNtBgRS9B4iQuC vyyJXoR/ClO73H5qKBOvJyh7psPrrShHbrapbxTOENkuMD7hAoOgHiKboKgh2pt1KE1t umjA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id cf17si8324619plb.52.2019.01.09.15.02.31; Wed, 09 Jan 2019 15:02:45 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726914AbfAIXAE (ORCPT + 99 others); Wed, 9 Jan 2019 18:00:04 -0500 Received: from mx1.redhat.com ([209.132.183.28]:41022 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726831AbfAIXAA (ORCPT ); Wed, 9 Jan 2019 18:00:00 -0500 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 23374C05FFE0; Wed, 9 Jan 2019 22:59:59 +0000 (UTC) Received: from treble.redhat.com (ovpn-125-32.rdu2.redhat.com [10.10.125.32]) by smtp.corp.redhat.com (Postfix) with ESMTP id EE19510A1820; Wed, 9 Jan 2019 22:59:56 +0000 (UTC) From: Josh Poimboeuf To: x86@kernel.org Cc: linux-kernel@vger.kernel.org, Ard Biesheuvel , Andy Lutomirski , Steven Rostedt , Peter Zijlstra , Ingo Molnar , Thomas Gleixner , Linus Torvalds , Masami Hiramatsu , Jason Baron , Jiri Kosina , David Laight , Borislav Petkov , Julia Cartwright , Jessica Yu , "H. Peter Anvin" , Nadav Amit , Rasmus Villemoes , Edward Cree , Daniel Bristot de Oliveira Subject: [PATCH v3 3/6] x86/static_call: Add out-of-line static call implementation Date: Wed, 9 Jan 2019 16:59:38 -0600 Message-Id: <30f0713894a415f13e0f0ea3d40595416db2f6d7.1547073843.git.jpoimboe@redhat.com> In-Reply-To: References: X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Wed, 09 Jan 2019 22:59:59 +0000 (UTC) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add the x86 out-of-line static call implementation. For each key, a permanent trampoline is created which is the destination for all static calls for the given key. The trampoline has a direct jump which gets patched by static_call_update() when the destination function changes. This relies on the fact that call destinations can be atomically updated as long as they don't cross cache line boundaries. Signed-off-by: Josh Poimboeuf --- arch/x86/Kconfig | 1 + arch/x86/include/asm/static_call.h | 27 +++++++++++++++++++++ arch/x86/kernel/Makefile | 1 + arch/x86/kernel/static_call.c | 38 ++++++++++++++++++++++++++++++ arch/x86/kernel/vmlinux.lds.S | 1 + include/asm-generic/vmlinux.lds.h | 15 ++++++++++++ 6 files changed, 83 insertions(+) create mode 100644 arch/x86/include/asm/static_call.h create mode 100644 arch/x86/kernel/static_call.c diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 6185d4f33296..421097322f1b 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -190,6 +190,7 @@ config X86 select HAVE_FUNCTION_ARG_ACCESS_API select HAVE_STACKPROTECTOR if CC_HAS_SANE_STACKPROTECTOR select HAVE_STACK_VALIDATION if X86_64 + select HAVE_STATIC_CALL select HAVE_RSEQ select HAVE_SYSCALL_TRACEPOINTS select HAVE_UNSTABLE_SCHED_CLOCK diff --git a/arch/x86/include/asm/static_call.h b/arch/x86/include/asm/static_call.h new file mode 100644 index 000000000000..fab5facade03 --- /dev/null +++ b/arch/x86/include/asm/static_call.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_STATIC_CALL_H +#define _ASM_STATIC_CALL_H + +#include + +/* + * This trampoline is used for out-of-line static calls. It has a direct jump + * which gets patched by static_call_update(). + * + * Trampolines are placed in the .static_call.text section to prevent two-byte + * tail calls to the trampoline and two-byte jumps from the trampoline. + * + * IMPORTANT: The JMP instruction's 4-byte destination must never cross + * cacheline boundaries! The patching code relies on that to ensure + * atomic updates. + */ +#define ARCH_DEFINE_STATIC_CALL_TRAMP(key, func) \ + asm(".pushsection .static_call.text, \"ax\" \n" \ + ".align 8 \n" \ + ".globl " STATIC_CALL_TRAMP_STR(key) " \n" \ + ".type " STATIC_CALL_TRAMP_STR(key) ", @function \n" \ + STATIC_CALL_TRAMP_STR(key) ": \n" \ + "jmp " #func " \n" \ + ".popsection \n") + +#endif /* _ASM_STATIC_CALL_H */ diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 00b7e27bc2b7..f1329a79fd3b 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -63,6 +63,7 @@ obj-y += tsc.o tsc_msr.o io_delay.o rtc.o obj-y += pci-iommu_table.o obj-y += resource.o obj-y += irqflags.o +obj-y += static_call.o obj-y += process.o obj-y += fpu/ diff --git a/arch/x86/kernel/static_call.c b/arch/x86/kernel/static_call.c new file mode 100644 index 000000000000..e6ef53fbce20 --- /dev/null +++ b/arch/x86/kernel/static_call.c @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include + +#define CALL_INSN_SIZE 5 + +void __ref arch_static_call_transform(void *site, void *tramp, void *func) +{ + s32 dest_relative; + unsigned char opcode; + void *(*poker)(void *, const void *, size_t); + void *insn = tramp; + + mutex_lock(&text_mutex); + + /* + * For x86-64, a 32-bit cross-modifying write to a call destination is + * safe as long as it's within a cache line. + */ + opcode = *(unsigned char *)insn; + if (opcode != 0xe8 && opcode != 0xe9) { + WARN_ONCE(1, "unexpected static call insn opcode 0x%x at %pS", + opcode, insn); + goto done; + } + + dest_relative = (long)(func) - (long)(insn + CALL_INSN_SIZE); + + poker = early_boot_irqs_disabled ? text_poke_early : text_poke; + poker(insn + 1, &dest_relative, sizeof(dest_relative)); + +done: + mutex_unlock(&text_mutex); +} +EXPORT_SYMBOL_GPL(arch_static_call_transform); diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S index 0d618ee634ac..17470e88ac40 100644 --- a/arch/x86/kernel/vmlinux.lds.S +++ b/arch/x86/kernel/vmlinux.lds.S @@ -128,6 +128,7 @@ SECTIONS CPUIDLE_TEXT LOCK_TEXT KPROBES_TEXT + STATIC_CALL_TEXT ALIGN_ENTRY_TEXT_BEGIN ENTRY_TEXT IRQENTRY_TEXT diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 3d7a6a9c2370..f2981a0161f2 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -320,6 +320,7 @@ __start_ro_after_init = .; \ *(.data..ro_after_init) \ JUMP_TABLE_DATA \ + STATIC_CALL_SITES \ __end_ro_after_init = .; #endif @@ -530,6 +531,10 @@ *(.kprobes.text) \ __kprobes_text_end = .; +#define STATIC_CALL_TEXT \ + ALIGN_FUNCTION(); \ + *(.static_call.text) + #define ENTRY_TEXT \ ALIGN_FUNCTION(); \ __entry_text_start = .; \ @@ -725,6 +730,16 @@ #define BUG_TABLE #endif +#ifdef CONFIG_HAVE_STATIC_CALL_INLINE +#define STATIC_CALL_SITES \ + . = ALIGN(8); \ + __start_static_call_sites = .; \ + KEEP(*(.static_call_sites)) \ + __stop_static_call_sites = .; +#else +#define STATIC_CALL_SITES +#endif + #ifdef CONFIG_UNWINDER_ORC #define ORC_UNWIND_TABLE \ . = ALIGN(4); \ -- 2.17.2