[Crash-utility] [PATCH v3] x86_64: VC exception stack support

Alexey Makhalov amakhalov at vmware.com
Mon Nov 30 17:48:29 UTC 2020


Linux-5.10 has introduced SEV-ES support. New (5th) exception
stack was added: 'VC_stack'.

'struct exception_stacks' cannot be used to obtain the size
of VC stack, as the size of VC stack is zero there. Try
another structure 'struct cea_exception_stacks' first as it
represents actual CPU entry area with valid stack sizes and
guard pages.

Handled the case if VC stack is not mapped (present).
It happens when SEV-ES is not active or not supported.

Signed-off-by: Alexey Makhalov <amakhalov at vmware.com>
---
 defs.h   |  1 +
 x86_64.c | 48 ++++++++++++++++++++++++++++++++++++------------
 2 files changed, 37 insertions(+), 12 deletions(-)

diff --git a/defs.h b/defs.h
index 9594950..4aeeef5 100644
--- a/defs.h
+++ b/defs.h
@@ -5913,6 +5913,7 @@ struct x86_64_pt_regs_offsets {
 struct x86_64_stkinfo {
 	ulong ebase[NR_CPUS][MAX_EXCEPTION_STACKS];
 	int esize[MAX_EXCEPTION_STACKS];
+	char available[NR_CPUS][MAX_EXCEPTION_STACKS];
 	ulong ibase[NR_CPUS];
 	int isize;
 	int NMI_stack_index;
diff --git a/x86_64.c b/x86_64.c
index 939c8a9..23a40a0 100644
--- a/x86_64.c
+++ b/x86_64.c
@@ -1369,6 +1369,7 @@ x86_64_ist_init(void)
 	ulong init_tss;
 	struct machine_specific *ms;
 	struct syment *boot_sp, *tss_sp, *ist_sp;
+	char *exc_stack_struct_name = NULL;
 
         ms = machdep->machspec;
 	if (!(tss_sp = per_cpu_symbol_search("per_cpu__init_tss"))) {
@@ -1444,25 +1445,40 @@ x86_64_ist_init(void)
 		return;
 	}
 
-	if (MEMBER_EXISTS("exception_stacks", "NMI_stack")) {
+	if (MEMBER_EXISTS("cea_exception_stacks", "NMI_stack")) {
+		/* The effective cpu entry area mapping with guard pages. */
+		exc_stack_struct_name = "cea_exception_stacks";
+	} else if (MEMBER_EXISTS("exception_stacks", "NMI_stack")) {
+		/* The exception stacks' physical storage. No guard pages and no VC stack. */
+		exc_stack_struct_name = "exception_stacks";
+	}
+	if (exc_stack_struct_name) {
                 for (i = 0; i < MAX_EXCEPTION_STACKS; i++) {
 			if (STREQ(ms->stkinfo.exception_stacks[i], "DEBUG"))
-				ms->stkinfo.esize[i] = MEMBER_SIZE("exception_stacks", "DB_stack");
+				ms->stkinfo.esize[i] = MEMBER_SIZE(exc_stack_struct_name, "DB_stack");
 			else if (STREQ(ms->stkinfo.exception_stacks[i], "NMI"))
-				ms->stkinfo.esize[i] = MEMBER_SIZE("exception_stacks", "NMI_stack");
+				ms->stkinfo.esize[i] = MEMBER_SIZE(exc_stack_struct_name, "NMI_stack");
 			else if (STREQ(ms->stkinfo.exception_stacks[i], "DOUBLEFAULT"))
-				ms->stkinfo.esize[i] = MEMBER_SIZE("exception_stacks", "DF_stack");
+				ms->stkinfo.esize[i] = MEMBER_SIZE(exc_stack_struct_name, "DF_stack");
 			else if (STREQ(ms->stkinfo.exception_stacks[i], "MCE"))
-				ms->stkinfo.esize[i] = MEMBER_SIZE("exception_stacks", "MCE_stack");
+				ms->stkinfo.esize[i] = MEMBER_SIZE(exc_stack_struct_name, "MCE_stack");
+			else if (STREQ(ms->stkinfo.exception_stacks[i], "VC"))
+				ms->stkinfo.esize[i] = MEMBER_SIZE(exc_stack_struct_name, "VC_stack");
 		}
 		/*
-	 	 *  Adjust the top-of-stack addresses down to the base stack address.
+		 *  Adjust the top-of-stack addresses down to the base stack address
+		 *  and set stack page availabilituy flag.
 		 */
 		for (c = 0; c < kt->cpus; c++) {
 			for (i = 0; i < MAX_EXCEPTION_STACKS; i++) {
-				if (ms->stkinfo.ebase[c][i] == 0) 
-					continue;
-				ms->stkinfo.ebase[c][i] -= ms->stkinfo.esize[i];
+				if (ms->stkinfo.ebase[c][i])
+					ms->stkinfo.ebase[c][i] -= ms->stkinfo.esize[i];
+
+				ms->stkinfo.available[c][i] = TRUE;
+				/* VC stack can be unmapped if SEV-ES is disabled or not supported. */
+				if (STREQ(ms->stkinfo.exception_stacks[i], "VC") &&
+				    !accessible(ms->stkinfo.ebase[c][i]))
+					ms->stkinfo.available[c][i] = FALSE;
 			}
 		}
 
@@ -1487,6 +1503,7 @@ x86_64_ist_init(void)
 			else
 				ms->stkinfo.esize[i] = esize;
 			ms->stkinfo.ebase[c][i] -= ms->stkinfo.esize[i];
+			ms->stkinfo.available[c][i] = TRUE;
 		}
 	}
 
@@ -2842,7 +2859,8 @@ x86_64_eframe_search(struct bt_info *bt)
 			    !(NUM_IN_BITMAP(bt->cpumask, c)))
 				continue;
                 	for (i = 0; i < MAX_EXCEPTION_STACKS; i++) {
-                        	if (ms->stkinfo.ebase[c][i] == 0)
+				if (ms->stkinfo.ebase[c][i] == 0 ||
+				    !ms->stkinfo.available[c][i])
                                 	break;
                                 bt->hp->esp = ms->stkinfo.ebase[c][i];
                                 fprintf(fp, "CPU %d %s EXCEPTION STACK:",
@@ -3288,7 +3306,8 @@ x86_64_in_exception_stack(struct bt_info *bt, int *estack_index)
 
         for (c = 0; !estack && (c < kt->cpus); c++) {
 		for (i = 0; i < MAX_EXCEPTION_STACKS; i++) {
-			if (ms->stkinfo.ebase[c][i] == 0)
+			if (ms->stkinfo.ebase[c][i] == 0 ||
+			    !ms->stkinfo.available[c][i])
 				break;
 			if ((rsp >= ms->stkinfo.ebase[c][i]) &&
 			    (rsp < (ms->stkinfo.ebase[c][i] + 
@@ -5097,7 +5116,7 @@ skip_stage:
                 	ms->stkinfo.esize[estack];
 		console("x86_64_get_dumpfile_stack_frame: searching %s estack at %lx\n", 
 			ms->stkinfo.exception_stacks[estack], bt->stackbase);
-		if (!(bt->stackbase)) 
+		if (!(bt->stackbase && ms->stkinfo.available[bt->tc->processor][estack]))
 			goto skip_stage;
 		bt->stackbuf = ms->irqstack;
 		alter_stackbuf(bt);
@@ -5380,6 +5399,8 @@ x86_64_exception_stacks_init(void)
 				ms->stkinfo.exception_stacks[ist-1] = "DOUBLEFAULT";
 			if (strstr(buf, "machine"))
 				ms->stkinfo.exception_stacks[ist-1] = "MCE";
+			if (strstr(buf, "vmm"))
+				ms->stkinfo.exception_stacks[ist-1] = "VC";
 		}
 	}
 
@@ -5737,6 +5758,9 @@ x86_64_display_machine_stats(void)
 			fprintf(fp, "%22s: %016lx",
 				buf, machdep->machspec->stkinfo.ebase[c][i]);
 
+			if (!machdep->machspec->stkinfo.available[c][i])
+				fprintf(fp, " [unavailable]");
+
 			if (hide_offline_cpu(c))
 				fprintf(fp, " [OFFLINE]\n");
 			else
-- 
2.11.0




More information about the Crash-utility mailing list