From d75cc118d0fdb75a4649a951e16e341ca87af199 Mon Sep 17 00:00:00 2001
From: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
Date: Tue, 10 Sep 2013 17:41:03 -0700
Subject: [PATCH 3/8] x86, smap: add debug code for CLAC opcode

In most cases, when SMAP enforced by calling CLAC, we expect it to be
previosly disabled (i.e., EFLAGS.AC=1) by a call to STAC. This debug
code verifies that this condition is met.

There are cases, however, in which CLAC is called without previously
having EFLAGS.AC=0. This is the case of error paths. For this reason,
debug functions are defined separately of the actual CLAC macros and
functions. This is to be able to selectively put debug points only
where required.

The CLAC debug code is implemented as an ALTERNATIVE, this is to
prevent that CPUs that do not support SMAP feature this code in case
it is enabled at build time.

Signed-off-by: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
---
 arch/x86/Kconfig            |  9 ++++++
 arch/x86/include/asm/smap.h | 77 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 86 insertions(+)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 34bc8ba..1ece076 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1563,6 +1563,15 @@ config X86_SMAP_DEBUG_STAC
 	  is called, EFLAGS.AC should be clear. This option verifies that this
 	  condition holds; otherwise, it generates an invalid opcode exception.
 
+config X86_SMAP_DEBUG_CLAC
+	def_bool n
+	prompt "Debug CLAC for SMAP" if X86_SMAP
+	---help---
+	  Enable code to debug problems related to the SMAP feature. When CLAC
+	  is called, EFLAGS.AC should be set in the majority of the cases. This
+	  option verifies that this condition holds; otherwise, it generates an
+	  invalid opcode exception.
+
 config EFI
 	bool "EFI runtime service support"
 	depends on ACPI
diff --git a/arch/x86/include/asm/smap.h b/arch/x86/include/asm/smap.h
index ecfd7a4..1954656 100644
--- a/arch/x86/include/asm/smap.h
+++ b/arch/x86/include/asm/smap.h
@@ -58,6 +58,44 @@
 
 #endif /* CONFIG_X86_SMAP_DEBUG_STAC */
 
+#ifdef CONFIG_X86_SMAP_DEBUG_CLAC
+
+#define __ASM_CLAC_NOP	ASM_NOP8 ;					\
+			ASM_NOP7 ;
+
+#ifdef CONFIG_X86_64
+#define __ASM_CLAC_DEBUG						\
+			pushfq ;					\
+			btq $X86_EFLAGS_AC_BIT, (%rsp) ;		\
+			jc 845f ;					\
+			ud2 ;						\
+		845:	addq $8, %rsp ;
+#else
+#define __ASM_CLAC_DEBUG						\
+			pushfl ;					\
+			btl $X86_EFLAGS_AC_BIT, (%esp) ;		\
+			jc 845f ;					\
+			ud2 ;						\
+		845:	addl $4, %esp ;
+#endif /* CONFIG_X86_64 */
+
+#define ASM_CLAC_DEBUG							\
+	661: __ASM_CLAC_NOP ;						\
+	662:								\
+	.pushsection .altinstr_replacement, "ax" ;			\
+	663: __ASM_CLAC_DEBUG ;						\
+	664:								\
+	.popsection ;							\
+	.pushsection .altinstructions, "a" ;				\
+	altinstruction_entry 661b, 663b, X86_FEATURE_SMAP, 662b-661b,	\
+							664b-663b ;	\
+	.popsection
+#else  /* CONFIG_X86_SMAP_DEBUG_CLAC */
+
+#define ASM_CLAC_DEBUG
+
+#endif /* CONFIG_X86_SMAP_DEBUG_CLAC */
+
 #include <asm/alternative-asm.h>
 
 #ifdef CONFIG_X86_SMAP
@@ -125,6 +163,45 @@
 
 #endif /* CONFIG_X86_SMAP_DEBUG_STAC */
 
+#ifdef CONFIG_X86_SMAP_DEBUG_CLAC
+
+#define __ASM_CLAC_DEBUG_NOP						\
+			ASM_NOP8					\
+			ASM_NOP7
+
+#ifdef CONFIG_X86_64
+#define __ASM_CLAC_DEBUG						\
+			"pushfq\n"					\
+			"btq $"__stringify(X86_EFLAGS_AC_BIT)		\
+							", (%%rsp)\n"	\
+			"jc 845f\n"					\
+			"ud2\n"						\
+			"845: addq $8, %%rsp\n"
+#else /* CONFIG_X86_64 */
+#define __ASM_CLAC_DEBUG						\
+			"pushfl\n"					\
+			"btl $"__stringify(X86_EFLAGS_AC_BIT)		\
+							", (%%esp)\n"	\
+			"jc 845f\n"					\
+			"ud2\n"						\
+			"845: addl $4, %%esp\n"
+#endif /* CONFIG_X86_64 */
+
+static __always_inline void clac_debug(void)
+{
+	alternative(__ASM_CLAC_DEBUG_NOP, __ASM_CLAC_DEBUG, X86_FEATURE_SMAP);
+}
+
+#define ASM_CLAC_DEBUG \
+	ALTERNATIVE(__ASM_CLAC_DEBUG_NOP, __ASM_CLAC_DEBUG, X86_FEATURE_SMAP)
+
+#else /* CONFIG_X86_SMAP_DEBUG_CLAC */
+
+#define ASM_CLAC_DEBUG
+static inline void clac_debug(void) { }
+
+#endif /* CONFIG_X86_SMAP_DEBUG_CLAC */
+
 #ifdef CONFIG_X86_SMAP
 
 static __always_inline void clac(void)
-- 
1.8.3.1

