mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Jim Kukunas <james.t.kukunas@linux.intel.com>
To: Linux Kernel <linux-kernel@vger.kernel.org>, tom.zanussi@linux.intel.com
Cc: Arjan van de Ven <arjan@linux.intel.com>,
	"H. Peter Anvin" <hpa@zytor.com>,
	tglx@linutronix.de, mingo@redhat.com, x86@kernel.org
Subject: [PATCH 10/11] x86/xip: resolve alternative instructions at build
Date: Mon, 23 Mar 2015 00:46:39 -0700	[thread overview]
Message-ID: <1427096800-30452-11-git-send-email-james.t.kukunas@linux.intel.com> (raw)
In-Reply-To: <1427096800-30452-1-git-send-email-james.t.kukunas@linux.intel.com>

Since the .text section can't be updated at run-time, remove the
.alternatives sections and update the .text at build time. To pick the
proper instructions, Kconfig options are exposed for each X86_FEATURE
that needed to be resolved. Each X86_FEATURE gets a corresponding
CONFIG_XIP_ENABLE_X86_FEATURE_ option. Based on whether this option
is set, a resolver macro is setup to either generate that instruction,
or the fallback. The resolver needs to be defined for each FEATURE, and
the proper one is chosen via preprocessor string pasting.

This approach is horrific and ugly. A better approach might be to add
an additional build step that, after generating the vmlinux file, goes
through the alternatives section and performs the fixups on the file.

At the very least, a script like mkcapflags.sh could generate the
resolver functions automatically. But since it's adding Kconfig
options, it would need to run unconditionally before any of the
config related Makefile targets.

Signed-off-by: Jim Kukunas <james.t.kukunas@linux.intel.com>
---
 arch/x86/Kconfig                       |  45 +++++++++
 arch/x86/include/asm/alternative-xip.h | 161 +++++++++++++++++++++++++++++++++
 arch/x86/include/asm/alternative.h     |   5 +
 arch/x86/kernel/alternative.c          |   7 ++
 arch/x86/kernel/cpu/bugs.c             |   2 +
 arch/x86/kernel/setup.c                |   2 +
 arch/x86/kernel/smpboot.c              |   2 +
 arch/x86/kernel/vmlinux.lds.S          |   2 +
 arch/x86/vdso/vma.c                    |   2 +
 9 files changed, 228 insertions(+)
 create mode 100644 arch/x86/include/asm/alternative-xip.h

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index f5fa02c..dff781d 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -313,6 +313,51 @@ config XIP_BASE
 	help
 	  The physical address for the beginning of the vmlinux file.
 
+menu "XIP Alternative Instructions"
+	depends on XIP_KERNEL
+
+	config XIP_ENABLE_X86_FEATURE_POPCNT
+	bool "Enable POPCNT alternative instructions"
+	default n
+
+	config XIP_ENABLE_X86_BUG_11AP
+	bool "Enable 11AP alternative instructions"
+	default n
+
+	config XIP_ENABLE_X86_FEATURE_XMM2
+	bool "Enable XMM2 alternative instructions"
+	default n
+
+	config XIP_ENABLE_X86_FEATURE_MFENCE_RDTSC
+	bool "Enable MFENCE_RDTSC alternative instructions"
+	default n
+
+	config XIP_ENABLE_X86_FEATURE_LFENCE_RDTSC
+	bool "Enable LFENCE_RDTSC alternative instructions"
+	default n
+
+	config XIP_ENABLE_X86_FEATURE_3DNOW
+	bool "Enable 3DNOW alternative instructions"
+	default n
+
+	config XIP_ENABLE_X86_FEATURE_XMM
+	bool "Enabled XMM alternative instructions"
+	default n
+
+	config XIP_ENABLE_X86_FEATURE_CLFLUSHOPT
+	bool "Enable CLFLUSHOPT alternative instructions"
+	default n
+
+	config XIP_ENABLE_X86_FEATURE_XSAVEOPT
+	bool "Enable XSAVEOPT alternative instructions"
+	default n
+
+	config XIP_ENABLE_X86_FEATURE_XSAVES
+	bool "Enable XSAVES alternative instructions"
+	default n
+
+endmenu
+
 config SMP
 	bool "Symmetric multi-processing support"
 	---help---
diff --git a/arch/x86/include/asm/alternative-xip.h b/arch/x86/include/asm/alternative-xip.h
new file mode 100644
index 0000000..84f544e
--- /dev/null
+++ b/arch/x86/include/asm/alternative-xip.h
@@ -0,0 +1,161 @@
+#ifndef _ASM_X86_ALTERNATIVE_XIP_H
+#define _ASM_X86_ALTERNATIVE_XIP_H
+
+/*
+ * Alternative instruction fixup for XIP
+ *
+ * Copyright (C) 2014 Intel Corporation
+ * Author: Jim Kukunas <james.t.kukunas@linux.intel.com>
+ *
+ * Since the kernel text is executing from storage and is
+ * read-only, we can't update the opcodes in-flight. Instead,
+ * resolve the alternatives at build time through preprocessor
+ * (ab)use.
+ */
+
+#ifdef CONFIG_SMP
+#define LOCK_PREFIX "\n\tlock; "
+#else
+#define LOCK_PREFIX ""
+#endif
+
+extern int poke_int3_handler(struct pt_regs *regs);
+
+/* TODO hook up to something like mkcapflags.sh */
+/* Unfortunately, each X86_FEATURE will need a corresponding define like this */
+#ifdef CONFIG_XIP_ENABLE_X86_FEATURE_POPCNT
+#define RESOLVE_X86_FEATURE_POPCNT(old, new) new
+#define RESOLVE_2_X86_FEATURE_POPCNT(old, new1, resolve1, new2) new2
+#else
+#define RESOLVE_X86_FEATURE_POPCNT(old, new) old
+#define RESOLVE_2_X86_FEATURE_POPCNT(old, new1, resolve1, new2) \
+	resolve1(old, new1)
+#endif
+
+#ifdef CONFIG_XIP_ENABLE_X86_BUG_11AP
+#define RESOLVE_X86_BUG_11AP(old, new) new
+#define RESOLVE_2_X86_BUG_11AP(old, new1, resolve1, new2) new2
+#else
+#define RESOLVE_X86_BUG_11AP(old, new) old
+#define RESOLVE_2_X86_BUG_11AP(old, new1, resolve1, new2) \
+	resolve1(old, new1)
+#endif
+
+#ifdef CONFIG_XIP_ENABLE_X86_FEATURE_XMM2
+#define RESOLVE_X86_FEATURE_XMM2(old, new) new
+#define RESOLVE_2_X86_FEATURE_XMM2(old, new1, resolve1, new2) new2
+#else
+#define RESOLVE_X86_FEATURE_XMM2(old, new) old
+#define RESOLVE_2_X86_FEATURE_XMM2(old, new1, resolve1, new2) \
+	resolve1(old, new1)
+#endif
+
+#ifdef CONFIG_XIP_ENABLE_X86_FEATURE_MFENCE_RDTSC
+#define RESOLVE_X86_FEATURE_MFENCE_RDTSC(old, new) new
+#define RESOLVE_2_X86_FEATURE_MFENCE_RDTSC(old, new1, resolve1, new2) new2
+#else
+#define RESOLVE_X86_FEATURE_MFENCE_RDTSC(old, new) old
+#define RESOLVE_2_X86_FEATURE_MFENCE_RDTSC(old, new1, resolve1, new2) \
+	resolve1(old, new1)
+#endif
+
+#ifdef CONFIG_XIP_ENABLE_X86_FEATURE_LFENCE_RDTSC
+#define RESOLVE_X86_FEATURE_LFENCE_RDTSC(old, new) new
+#define RESOLVE_2_X86_FEATURE_LFENCE_RDTSC(old, new1, resolve1, new2) new2
+#else
+#define RESOLVE_X86_FEATURE_LFENCE_RDTSC(old, new) old
+#define RESOLVE_2_X86_FEATURE_LFENCE_RDTSC(old, new1, resolve1, new2) \
+	resolve1(old, new1)
+#endif
+
+#ifdef CONFIG_XIP_ENABLE_X86_FEATURE_3DNOW
+#define RESOLVE_X86_FEATURE_3DNOW(old, new) new
+#define RESOLVE_2_X86_FEATURE_3DNOW(old, new1, resolve1, new2) new2
+#else
+#define RESOLVE_X86_FEATURE_3DNOW(old, new) old
+#define RESOLVE_2_X86_FEATURE_3DNOW(old, new1, resolve1, new2) \
+	resolve1(old, new1)
+#endif
+
+#ifdef CONFIG_XIP_ENABLE_X86_FEATURE_XMM
+#define RESOLVE_X86_FEATURE_XMM(old, new) new
+#define RESOLVE_2_X86_FEATURE_XMM(old, new1, resolve1, new2) new2
+#else
+#define RESOLVE_X86_FEATURE_XMM(old, new) old
+#define RESOLVE_2_X86_FEATURE_XMM(old, new1, resolve1, new2) \
+	resolve1(old, new1)
+#endif
+
+#ifdef CONFIG_XIP_ENABLE_X86_FEATURE_CLFLUSHOPT
+#define RESOLVE_X86_FEATURE_CLFLUSHOPT(old, new) new
+#define RESOLVE_2_X86_FEATURE_CLFLUSHOPT(old, new1, resolve1, new2) new2
+#else
+#define RESOLVE_X86_FEATURE_CLFLUSHOPT(old, new) old
+#define RESOLVE_2_X86_FEATURE_CLFLUSHOPT(old, new1, resolve1, new2) \
+	resolve1(old, new1)
+#endif
+
+#ifdef CONFIG_XIP_ENABLE_X86_FEATURE_XSAVEOPT
+#define RESOLVE_X86_FEATURE_XSAVEOPT(old, new) new
+#define RESOLVE_2_X86_FEATURE_XSAVEOPT(old, new1, resolve1, new2) new2
+#else
+#define RESOLVE_X86_FEATURE_XSAVEOPT(old, new) old
+#define RESOLVE_2_X86_FEATURE_XSAVEOPT(old, new1, resovle1, new2) \
+	resolve1(old, new1)
+#endif
+
+#ifdef CONFIG_XIP_ENABLE_X86_FEATURE_XSAVES
+#define RESOLVE_X86_FEATURE_XSAVES(old, new) new
+#define RESOLVE_2_X86_FEATURE_XSAVES(old, new1, resolve1, new2) new2
+#else
+#define RESOLVE_X86_FEATURE_XSAVES(old, new) old
+#define RESOLVE_2_X86_FEATURE_XSAVES(old, new1, resolve1, new2) \
+	resolve1(old, new1)
+#endif
+
+#define ASM_OUTPUT2(a...) a
+#define ASM_NO_INPUT_CLOBBER(clbr...) "i" (0) : clbr
+
+#define __ALTERNATIVE(oldinstr, newinstr, resolve) \
+	resolve(oldinstr, newinstr)
+
+#define __ALTERNATIVE_2(oldinstr, instr1, resolve1, instr2, resolve2) \
+	resolve2(oldinstr, instr1, resolve1, instr2)
+
+#define ALTERNATIVE(oldinstr, newinstr, feature) \
+	RESOLVE_##feature(oldinstr, newinstr)
+
+#define ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2) \
+	RESOLVE_2_##feature2(oldinstr, newinstr1, feature1, newinstr2)
+
+#define alternative(oldinstr, newinstr, feature) \
+	asm volatile(__ALTERNATIVE(oldinstr, newinstr, RESOLVE_##feature) \
+		: : : "memory")
+
+#define alternative_input(oldinstr, newinstr, feature, input...) \
+	asm volatile(__ALTERNATIVE(oldinstr, newinstr, RESOLVE_##feature) \
+		: : "i" (0), input)
+
+#define alternative_input_2(oldinstr, newinstr1, feature1, newinstr2, \
+			   feature2, input...) \
+	asm volatile( \
+		__ALTERNATIVE_2(oldinstr, newinstr1, RESOLVE_##feature1,\
+			newinstr2, RESOLVE_2_ ##feature2) \
+		: : "i" (0), ## input)
+
+#define alternative_io(oldinstr, newinstr, feature, output, input...) \
+	asm volatile(__ALTERNATIVE(oldinstr, newinstr, RESOLVE_##feature) \
+		: output : "i" (0), ##input)
+
+#define alternative_call(oldfunc, newfunc, feature, output, input...) \
+	asm volatile(__ALTERNATIVE("call %P[[old]", "call %P[new]", \
+		RESOLVE_##feature) : output : [old] "i" (oldfunc), \
+		[new] "i" (newfunc), input)
+
+#define alternative_call_2(oldfunc, newfunc1, feature1, newfunc2, feature2, \
+		output, intput...) \
+	asm volatile(ALTERNATIVE_2("call %P[old]", "call %P[new1]", feature1, \
+		"call %P[new2]", feature2) \
+		: output : [old] "i" (oldfunc), [new1] "i" (newfunc1), \
+		[new2] "i" (newfunc2), input)
+#endif
diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h
index 473bdbe..559a2cd 100644
--- a/arch/x86/include/asm/alternative.h
+++ b/arch/x86/include/asm/alternative.h
@@ -7,6 +7,10 @@
 #include <asm/asm.h>
 #include <asm/ptrace.h>
 
+#ifdef CONFIG_XIP_KERNEL
+#include <asm/alternative-xip.h>
+#else
+
 /*
  * Alternative inline assembly for SMP.
  *
@@ -242,4 +246,5 @@ extern void *text_poke(void *addr, const void *opcode, size_t len);
 extern int poke_int3_handler(struct pt_regs *regs);
 extern void *text_poke_bp(void *addr, const void *opcode, size_t len, void *handler);
 
+#endif /* !CONFIG_XIP_KERNEL */
 #endif /* _ASM_X86_ALTERNATIVE_H */
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index 703130f..c337552 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -21,6 +21,8 @@
 #include <asm/io.h>
 #include <asm/fixmap.h>
 
+#ifndef CONFIG_XIP_KERNEL
+
 #define MAX_PATCH_LEN (255-1)
 
 static int __initdata_or_module debug_alternative;
@@ -590,6 +592,8 @@ static void do_sync_core(void *info)
 	sync_core();
 }
 
+#endif /* !CONFIG_XIP_KERNEL */
+
 static bool bp_patching_in_progress;
 static void *bp_int3_handler, *bp_int3_addr;
 
@@ -611,6 +615,8 @@ int poke_int3_handler(struct pt_regs *regs)
 
 }
 
+#ifndef CONFIG_XIP_KERNEL
+
 /**
  * text_poke_bp() -- update instructions on live kernel on SMP
  * @addr:	address to patch
@@ -674,4 +680,5 @@ void *text_poke_bp(void *addr, const void *opcode, size_t len, void *handler)
 
 	return addr;
 }
+#endif /* !CONFIG_XIP_KERNEL */
 
diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
index 0344534..4c184a5 100644
--- a/arch/x86/kernel/cpu/bugs.c
+++ b/arch/x86/kernel/cpu/bugs.c
@@ -83,7 +83,9 @@ void __init check_bugs(void)
 
 	init_utsname()->machine[1] =
 		'0' + (boot_cpu_data.x86 > 6 ? 6 : boot_cpu_data.x86);
+#ifndef CONFIG_XIP_KERNEL
 	alternative_instructions();
+#endif
 
 	/*
 	 * kernel_fpu_begin/end() in check_fpu() relies on the patched
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index f044453..ed541b9 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -1275,7 +1275,9 @@ void __init setup_arch(char **cmdline_p)
 
 	mcheck_init();
 
+#ifndef CONFIG_XIP_KERNEL
 	arch_init_ideal_nops();
+#endif
 
 	register_refined_jiffies(CLOCK_TICK_RATE);
 
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index febc6aa..bebd323 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -797,7 +797,9 @@ static int do_boot_cpu(int apicid, int cpu, struct task_struct *idle)
 	unsigned long timeout;
 
 	/* Just in case we booted with a single CPU. */
+#ifndef CONFIG_XIP_KERNEL
 	alternatives_enable_smp();
+#endif
 
 	idle->thread.sp = (unsigned long) (((struct pt_regs *)
 			  (THREAD_SIZE +  task_stack_page(idle))) - 1);
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index 59a9edb..fc66ebf 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -228,6 +228,7 @@ SECTIONS
 	}
 #endif
 
+#ifndef CONFIG_XIP_KERNEL
 	/*
 	 * start address and size of operations which during runtime
 	 * can be patched with virtualization friendly instructions or
@@ -261,6 +262,7 @@ SECTIONS
 	.altinstr_replacement : AT(ADDR(.altinstr_replacement) - LOAD_OFFSET) {
 		*(.altinstr_replacement)
 	}
+#endif
 
 	/*
 	 * struct iommu_table_entry entries are injected in this section.
diff --git a/arch/x86/vdso/vma.c b/arch/x86/vdso/vma.c
index 1c9f750..ba336ef 100644
--- a/arch/x86/vdso/vma.c
+++ b/arch/x86/vdso/vma.c
@@ -34,9 +34,11 @@ void __init init_vdso_image(const struct vdso_image *image)
 		image->text_mapping.pages[i] =
 			virt_to_page(image->data + i*PAGE_SIZE);
 
+#ifndef CONFIG_XIP_KERNEL
 	apply_alternatives((struct alt_instr *)(image->data + image->alt),
 			   (struct alt_instr *)(image->data + image->alt +
 						image->alt_len));
+#endif
 }
 
 struct linux_binprm;
-- 
2.1.0


  parent reply	other threads:[~2015-03-23  7:55 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-03-23  7:46 [RFC] x86 XIP Jim Kukunas
2015-03-23  7:46 ` [PATCH 01/11] x86/xip: add XIP_KERNEL and XIP_BASE options Jim Kukunas
2015-03-23  7:46 ` [PATCH 02/11] x86/xip: Update address of sections in linker script Jim Kukunas
2015-03-23  7:46 ` [PATCH 03/11] x86/xip: copy writable sections into RAM Jim Kukunas
2015-03-23  7:46 ` [PATCH 04/11] x86/xip: XIP boot trampoline page tables Jim Kukunas
2015-03-23  7:46 ` [PATCH 05/11] x86/xip: reserve memblock for only data Jim Kukunas
2015-03-23  7:46 ` [PATCH 06/11] x86/xip: after paging trampoline, discard PMDs above _brk Jim Kukunas
2015-03-23  7:46 ` [PATCH 07/11] x86/xip: make e820_add_kernel_range() a NOP Jim Kukunas
2015-03-23  7:46 ` [PATCH 08/11] x86/xip: in setup_arch(), handle resource physical addr Jim Kukunas
2015-03-23  7:46 ` [PATCH 09/11] x86/xip: snip the kernel text out of the memory mapping Jim Kukunas
2015-03-23  7:46 ` Jim Kukunas [this message]
2015-03-23  8:33   ` [PATCH 10/11] x86/xip: resolve alternative instructions at build Borislav Petkov
2015-03-23  8:38     ` Borislav Petkov
2015-03-25  0:50     ` Jim Kukunas
2015-03-25  8:44       ` Borislav Petkov
2015-03-23 22:40   ` Paul Bolle
2015-03-23  7:46 ` [PATCH 11/11] x86/xip: update _va() and _pa() macros Jim Kukunas
2015-03-23  8:09   ` Ingo Molnar
2015-03-23 15:09     ` Borislav Petkov
2015-03-23  8:07 ` [RFC] x86 XIP Ingo Molnar
2015-03-25  0:14   ` Jim Kukunas

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1427096800-30452-11-git-send-email-james.t.kukunas@linux.intel.com \
    --to=james.t.kukunas@linux.intel.com \
    --cc=arjan@linux.intel.com \
    --cc=hpa@zytor.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=tglx@linutronix.de \
    --cc=tom.zanussi@linux.intel.com \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®