[v3,45/75] x86/dumpstack/64: Handle #VC exception stacks
diff mbox series

Message ID 20200428151725.31091-46-joro@8bytes.org
State New
Headers show
Series
  • x86: SEV-ES Guest Support
Related show

Commit Message

Joerg Roedel April 28, 2020, 3:16 p.m. UTC
From: Joerg Roedel <jroedel@suse.de>

Make the stack unwinder aware of the IST stacks for the #VC exception
handler.

Signed-off-by: Joerg Roedel <jroedel@suse.de>
---
 arch/x86/include/asm/cpu_entry_area.h |  1 +
 arch/x86/include/asm/sev-es.h         | 13 ++++++++
 arch/x86/include/asm/stacktrace.h     |  4 +++
 arch/x86/kernel/dumpstack_64.c        | 47 +++++++++++++++++++++++++++
 arch/x86/kernel/sev-es.c              | 26 +++++++++++++++
 5 files changed, 91 insertions(+)

Comments

Borislav Petkov May 22, 2020, 1:06 p.m. UTC | #1
On Tue, Apr 28, 2020 at 05:16:55PM +0200, Joerg Roedel wrote:
> diff --git a/arch/x86/include/asm/stacktrace.h b/arch/x86/include/asm/stacktrace.h
> index 14db05086bbf..2f3534ef4b5f 100644
> --- a/arch/x86/include/asm/stacktrace.h
> +++ b/arch/x86/include/asm/stacktrace.h
> @@ -21,6 +21,10 @@ enum stack_type {
>  	STACK_TYPE_ENTRY,
>  	STACK_TYPE_EXCEPTION,
>  	STACK_TYPE_EXCEPTION_LAST = STACK_TYPE_EXCEPTION + N_EXCEPTION_STACKS-1,
> +#ifdef CONFIG_X86_64

CONFIG_AMD_MEM_ENCRYPT

> +	STACK_TYPE_VC,
> +	STACK_TYPE_VC_LAST = STACK_TYPE_VC + N_VC_STACKS - 1,
> +#endif
>  };
>  
>  struct stack_info {
> diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c
> index 87b97897a881..2468963c1424 100644
> --- a/arch/x86/kernel/dumpstack_64.c
> +++ b/arch/x86/kernel/dumpstack_64.c
> @@ -18,6 +18,7 @@
>  
>  #include <asm/cpu_entry_area.h>
>  #include <asm/stacktrace.h>
> +#include <asm/sev-es.h>
>  
>  static const char * const exception_stack_names[] = {
>  		[ ESTACK_DF	]	= "#DF",
> @@ -47,6 +48,9 @@ const char *stack_type_name(enum stack_type type)
>  	if (type >= STACK_TYPE_EXCEPTION && type <= STACK_TYPE_EXCEPTION_LAST)
>  		return exception_stack_names[type - STACK_TYPE_EXCEPTION];
>  
> +	if (type >= STACK_TYPE_VC && type <= STACK_TYPE_VC_LAST)

That test can be inside vc_stack_name() so that it gets optimized away
for !CONFIG_AMD_MEM_ENCRYPT and there's no need for ifdeffery.

Patch
diff mbox series

diff --git a/arch/x86/include/asm/cpu_entry_area.h b/arch/x86/include/asm/cpu_entry_area.h
index 85aac6c63653..e4216caad01a 100644
--- a/arch/x86/include/asm/cpu_entry_area.h
+++ b/arch/x86/include/asm/cpu_entry_area.h
@@ -192,6 +192,7 @@  struct cpu_entry_area {
 
 DECLARE_PER_CPU(struct cpu_entry_area *, cpu_entry_area);
 DECLARE_PER_CPU(struct cea_exception_stacks *, cea_exception_stacks);
+DECLARE_PER_CPU(struct cea_vmm_exception_stacks *, cea_vmm_exception_stacks);
 
 extern void setup_cpu_entry_areas(void);
 extern void cea_set_pte(void *cea_vaddr, phys_addr_t pa, pgprot_t flags);
diff --git a/arch/x86/include/asm/sev-es.h b/arch/x86/include/asm/sev-es.h
index e1ed963a57ec..265da8351475 100644
--- a/arch/x86/include/asm/sev-es.h
+++ b/arch/x86/include/asm/sev-es.h
@@ -9,6 +9,8 @@ 
 #define __ASM_ENCRYPTED_STATE_H
 
 #include <linux/types.h>
+
+#include <asm/stacktrace.h>
 #include <asm/insn.h>
 
 #define GHCB_SEV_INFO		0x001UL
@@ -76,4 +78,15 @@  static inline u64 lower_bits(u64 val, unsigned int bits)
 extern void vc_no_ghcb(void);
 extern bool vc_boot_ghcb(struct pt_regs *regs);
 
+enum stack_type;
+
+#ifdef CONFIG_AMD_MEM_ENCRYPT
+const char *vc_stack_name(enum stack_type type);
+#else /* CONFIG_AMD_MEM_ENCRYPT */
+static inline const char *vc_stack_name(enum stack_type type)
+{
+	return NULL;
+}
+#endif /* CONFIG_AMD_MEM_ENCRYPT*/
+
 #endif
diff --git a/arch/x86/include/asm/stacktrace.h b/arch/x86/include/asm/stacktrace.h
index 14db05086bbf..2f3534ef4b5f 100644
--- a/arch/x86/include/asm/stacktrace.h
+++ b/arch/x86/include/asm/stacktrace.h
@@ -21,6 +21,10 @@  enum stack_type {
 	STACK_TYPE_ENTRY,
 	STACK_TYPE_EXCEPTION,
 	STACK_TYPE_EXCEPTION_LAST = STACK_TYPE_EXCEPTION + N_EXCEPTION_STACKS-1,
+#ifdef CONFIG_X86_64
+	STACK_TYPE_VC,
+	STACK_TYPE_VC_LAST = STACK_TYPE_VC + N_VC_STACKS - 1,
+#endif
 };
 
 struct stack_info {
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c
index 87b97897a881..2468963c1424 100644
--- a/arch/x86/kernel/dumpstack_64.c
+++ b/arch/x86/kernel/dumpstack_64.c
@@ -18,6 +18,7 @@ 
 
 #include <asm/cpu_entry_area.h>
 #include <asm/stacktrace.h>
+#include <asm/sev-es.h>
 
 static const char * const exception_stack_names[] = {
 		[ ESTACK_DF	]	= "#DF",
@@ -47,6 +48,9 @@  const char *stack_type_name(enum stack_type type)
 	if (type >= STACK_TYPE_EXCEPTION && type <= STACK_TYPE_EXCEPTION_LAST)
 		return exception_stack_names[type - STACK_TYPE_EXCEPTION];
 
+	if (type >= STACK_TYPE_VC && type <= STACK_TYPE_VC_LAST)
+		return vc_stack_name(type);
+
 	return NULL;
 }
 
@@ -84,6 +88,46 @@  struct estack_pages estack_pages[CEA_ESTACK_PAGES] ____cacheline_aligned = {
 	EPAGERANGE(MCE),
 };
 
+static bool in_vc_exception_stack(unsigned long *stack, struct stack_info *info)
+{
+#ifdef CONFIG_AMD_MEM_ENCRYPT
+	unsigned long begin, end, stk = (unsigned long)stack;
+	struct cea_vmm_exception_stacks *vc_stacks;
+	struct pt_regs *regs;
+	enum stack_type type;
+	int i;
+
+	vc_stacks = __this_cpu_read(cea_vmm_exception_stacks);
+
+	/* Already initialized? */
+	if (!vc_stacks)
+		return false;
+
+	for (i = 0; i < N_VC_STACKS; i++) {
+		type  = STACK_TYPE_VC_LAST - i;
+		begin = (unsigned long)vc_stacks->stacks[i].stack;
+		end   = begin + sizeof(vc_stacks->stacks[i].stack);
+
+		if (stk >= begin && stk < end)
+			goto found;
+	}
+
+	return false;
+
+found:
+
+	regs		= (struct pt_regs *)end - 1;
+	info->type	= type;
+	info->begin	= (unsigned long *)begin;
+	info->end	= (unsigned long *)end;
+	info->next_sp	= (unsigned long *)regs->sp;
+
+	return true;
+#else
+	return false;
+#endif
+}
+
 static bool in_exception_stack(unsigned long *stack, struct stack_info *info)
 {
 	unsigned long begin, end, stk = (unsigned long)stack;
@@ -173,6 +217,9 @@  int get_stack_info(unsigned long *stack, struct task_struct *task,
 	if (in_entry_stack(stack, info))
 		goto recursion_check;
 
+	if (in_vc_exception_stack(stack, info))
+		goto recursion_check;
+
 	goto unknown;
 
 recursion_check:
diff --git a/arch/x86/kernel/sev-es.c b/arch/x86/kernel/sev-es.c
index e5d87f2af357..dd60d24db3d0 100644
--- a/arch/x86/kernel/sev-es.c
+++ b/arch/x86/kernel/sev-es.c
@@ -18,6 +18,7 @@ 
 #include <linux/mm.h>
 
 #include <asm/cpu_entry_area.h>
+#include <asm/stacktrace.h>
 #include <asm/trap_defs.h>
 #include <asm/sev-es.h>
 #include <asm/insn-eval.h>
@@ -34,6 +35,9 @@  static struct ghcb boot_ghcb_page __bss_decrypted __aligned(PAGE_SIZE);
  * cleared
  */
 static struct ghcb __initdata *boot_ghcb;
+DEFINE_PER_CPU(struct cea_vmm_exception_stacks *, cea_vmm_exception_stacks);
+
+static char vc_stack_names[N_VC_STACKS][8];
 
 /* #VC handler runtime per-cpu data */
 struct sev_es_runtime_data {
@@ -240,6 +244,16 @@  static void __init sev_es_init_ghcb(int cpu)
 	memset(&data->ghcb_page, 0, sizeof(data->ghcb_page));
 }
 
+static void __init init_vc_stack_names(void)
+{
+	int i;
+
+	for (i = 0; i < N_VC_STACKS; i++) {
+		snprintf(vc_stack_names[i], sizeof(vc_stack_names[i]),
+			 "#VC%d", i);
+	}
+}
+
 static void __init sev_es_setup_vc_stack(int cpu)
 {
 	struct vmm_exception_stacks *stack;
@@ -272,6 +286,8 @@  static void __init sev_es_setup_vc_stack(int cpu)
 	tss         = per_cpu_ptr(&cpu_tss_rw, cpu);
 
 	tss->x86_tss.ist[IST_INDEX_VC] = (unsigned long)first_stack + size;
+
+	per_cpu(cea_vmm_exception_stacks, cpu) = &cea->vc_stacks;
 }
 
 void __init sev_es_init_vc_handling(void)
@@ -290,6 +306,16 @@  void __init sev_es_init_vc_handling(void)
 		sev_es_init_ghcb(cpu);
 		sev_es_setup_vc_stack(cpu);
 	}
+
+	init_vc_stack_names();
+}
+
+const char *vc_stack_name(enum stack_type type)
+{
+	if (type < STACK_TYPE_VC || type > STACK_TYPE_VC_LAST)
+		return NULL;
+
+	return vc_stack_names[type - STACK_TYPE_VC];
 }
 
 static void __init vc_early_vc_forward_exception(struct es_em_ctxt *ctxt)