[Crash-utility] [PATCH 1/5] Move Xen Dom0 handling into xen_dom0.c

Petr Tesarik ptesarik at suse.com
Thu Sep 24 16:17:10 UTC 2015


The information in struct xen_kdump_data is needed if the dump file
is a Dom0 dump, regardless of file format. It has been part of
netdump.c, because this has been the only file format for this kind
of dump, but since makedumpfile can save it in compressed dump format,
there is some common code for both netdump.c and diskdump.c.

Signed-off-by: Petr Tesarik <ptesarik at suse.com>
---
 Makefile   |   9 ++-
 ia64.c     |   1 +
 netdump.c  | 248 ++++++++-----------------------------------------------------
 netdump.h  |  53 -------------
 x86.c      |   1 +
 x86_64.c   |   1 +
 xen_dom0.c | 215 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 xen_dom0.h |  74 ++++++++++++++++++
 8 files changed, 332 insertions(+), 270 deletions(-)
 create mode 100644 xen_dom0.c
 create mode 100644 xen_dom0.h

diff --git a/Makefile b/Makefile
index 3c38ff5..3ab138a 100644
--- a/Makefile
+++ b/Makefile
@@ -70,7 +70,8 @@ CFILES=main.c tools.c global_data.c memory.c filesys.c help.c task.c \
 	unwind_x86_32_64.c unwind_arm.c \
 	xen_hyper.c xen_hyper_command.c xen_hyper_global_data.c \
 	xen_hyper_dump_tables.c kvmdump.c qemu.c qemu-load.c sadump.c ipcs.c \
-	ramdump.c vmware_vmss.c
+	ramdump.c vmware_vmss.c \
+	xen_dom0.c
 
 SOURCE_FILES=${CFILES} ${GENERIC_HFILES} ${MCORE_HFILES} \
 	${REDHAT_CFILES} ${REDHAT_HFILES} ${UNWIND_HFILES} \
@@ -88,7 +89,8 @@ OBJECT_FILES=main.o tools.o global_data.o memory.o filesys.o help.o task.o \
 	unwind_x86_32_64.o unwind_arm.o \
 	xen_hyper.o xen_hyper_command.o xen_hyper_global_data.o \
 	xen_hyper_dump_tables.o kvmdump.o qemu.o qemu-load.o sadump.o ipcs.o \
-	ramdump.o vmware_vmss.o
+	ramdump.o vmware_vmss.o \
+	xen_dom0.o
 
 MEMORY_DRIVER_FILES=memory_driver/Makefile memory_driver/crash.c memory_driver/README
 
@@ -497,6 +499,9 @@ xen_hyper_global_data.o: ${GENERIC_HFILES} xen_hyper_global_data.c
 xen_hyper_dump_tables.o: ${GENERIC_HFILES} xen_hyper_dump_tables.c
 	${CC} -c ${CRASH_CFLAGS} xen_hyper_dump_tables.c ${WARNING_OPTIONS} ${WARNING_ERROR}
 
+xen_dom0.o: ${GENERIC_HFILES} xen_dom0.c
+	${CC} -c ${CRASH_CFLAGS} xen_dom0.c ${WARNING_OPTIONS} ${WARNING_ERROR}
+
 ramdump.o: ${GENERIC_HFILES} ${REDHAT_HFILES} ramdump.c
 	${CC} -c ${CRASH_CFLAGS} ramdump.c ${WARNING_OPTIONS} ${WARNING_ERROR}
 
diff --git a/ia64.c b/ia64.c
index 6df7afd..60fcf20 100644
--- a/ia64.c
+++ b/ia64.c
@@ -3848,6 +3848,7 @@ ia64_vtop_xen_wpt(ulong vaddr, physaddr_t *paddr, ulong *pgd, int verbose, int u
 }
 
 #include "netdump.h"
+#include "xen_dom0.h"
 
 /*
  *  Determine the relocatable physical address base.
diff --git a/netdump.c b/netdump.c
index 9dd3722..38ddc8f 100644
--- a/netdump.c
+++ b/netdump.c
@@ -21,10 +21,10 @@
 #include "defs.h"
 #include "netdump.h"
 #include "sadump.h"
+#include "xen_dom0.h"
 
 static struct vmcore_data vmcore_data = { 0 };
 static struct vmcore_data *nd = &vmcore_data;
-static struct xen_kdump_data xen_kdump_data = { 0 };
 static struct proc_kcore_data proc_kcore_data = { 0 };
 static struct proc_kcore_data *pkd = &proc_kcore_data;
 static void netdump_print(char *, ...);
@@ -40,7 +40,6 @@ static void get_netdump_regs_ppc(struct bt_info *, ulong *, ulong *);
 static void get_netdump_regs_ppc64(struct bt_info *, ulong *, ulong *);
 static void get_netdump_regs_arm(struct bt_info *, ulong *, ulong *);
 static void get_netdump_regs_arm64(struct bt_info *, ulong *, ulong *);
-static physaddr_t xen_kdump_p2m(physaddr_t);
 static void check_dumpfile_size(char *);
 static int proc_kcore_init_32(FILE *fp);
 static int proc_kcore_init_64(FILE *fp);
@@ -1169,50 +1168,7 @@ netdump_memory_dump(FILE *fp)
 	netdump_print("            task_struct: %lx\n", nd->task_struct);
 	netdump_print("              page_size: %d\n", nd->page_size);
 	netdump_print("           switch_stack: %lx\n", nd->switch_stack);
-	netdump_print("         xen_kdump_data: %s\n",
-		XEN_CORE_DUMPFILE() ? " " : "(unused)");
-	if (XEN_CORE_DUMPFILE()) {
-		netdump_print("                    flags: %lx (", nd->xen_kdump_data->flags);
-		others = 0;
-        	if (nd->xen_kdump_data->flags & KDUMP_P2M_INIT)
-                	netdump_print("%sKDUMP_P2M_INIT", others++ ? "|" : "");
-        	if (nd->xen_kdump_data->flags & KDUMP_CR3)
-                	netdump_print("%sKDUMP_CR3", others++ ? "|" : "");
-        	if (nd->xen_kdump_data->flags & KDUMP_MFN_LIST)
-                	netdump_print("%sKDUMP_MFN_LIST", others++ ? "|" : "");
-		netdump_print(")\n");
-		netdump_print("                  p2m_mfn: %lx\n", 
-			nd->xen_kdump_data->p2m_mfn);
-		netdump_print("                      cr3: %lx\n", 
-			nd->xen_kdump_data->cr3);
-		netdump_print("            last_mfn_read: %lx\n", 
-			nd->xen_kdump_data->last_mfn_read);
-		netdump_print("            last_pmd_read: %lx\n", 
-			nd->xen_kdump_data->last_pmd_read);
-		netdump_print("                     page: %lx\n", 
-			nd->xen_kdump_data->page);
-		netdump_print("                 accesses: %ld\n", 
-			nd->xen_kdump_data->accesses);
-		netdump_print("               cache_hits: %ld ", 
-			nd->xen_kdump_data->cache_hits);
-      		if (nd->xen_kdump_data->accesses)
-                	netdump_print("(%ld%%)", 
-			    nd->xen_kdump_data->cache_hits * 100 / nd->xen_kdump_data->accesses);
-		netdump_print("\n               p2m_frames: %d\n", 
-			nd->xen_kdump_data->p2m_frames);
-		netdump_print("           xen_phys_start: %lx\n", 
-			nd->xen_kdump_data->xen_phys_start);
-		netdump_print("        xen_major_version: %d\n", 
-			nd->xen_kdump_data->xen_major_version);
-		netdump_print("        xen_minor_version: %d\n", 
-			nd->xen_kdump_data->xen_minor_version);
-		netdump_print("       p2m_mfn_frame_list: %lx\n", 
-			nd->xen_kdump_data->p2m_mfn_frame_list);
-		for (i = 0; i < nd->xen_kdump_data->p2m_frames; i++)
-			netdump_print("%lx ", 
-				nd->xen_kdump_data->p2m_mfn_frame_list[i]);
-		if (i) netdump_print("\n");
-	}
+	dump_xen_kdump_data(fp);
 	netdump_print("     num_prstatus_notes: %d\n", nd->num_prstatus_notes);
 	netdump_print("         num_qemu_notes: %d\n", nd->num_qemu_notes);
 	netdump_print("             vmcoreinfo: %lx\n", (ulong)nd->vmcoreinfo);
@@ -2022,36 +1978,36 @@ dump_Elf32_Nhdr(Elf32_Off offset, int store)
                 	netdump_print("(XEN_ELFNOTE_CRASH_INFO)\n");
 		xen_core = TRUE;
 		if (store) { 
+			struct xen_kdump_data *xkd = get_xen_kdump_data();
 			pc->flags |= XEN_CORE;
-			nd->xen_kdump_data = &xen_kdump_data;
-			nd->xen_kdump_data->last_mfn_read = UNINITIALIZED;
-			nd->xen_kdump_data->last_pmd_read = UNINITIALIZED;
+			xkd->last_mfn_read = UNINITIALIZED;
+			xkd->last_pmd_read = UNINITIALIZED;
 
 			if ((note->n_type == NT_XEN_KDUMP_CR3) &&
 			    ((note->n_descsz/sizeof(ulong)) == 1)) {
-				nd->xen_kdump_data->flags |= KDUMP_CR3;
+				xkd->flags |= KDUMP_CR3;
 				/*
 				 *  Use the first cr3 found.
 				 */
-				if (!nd->xen_kdump_data->cr3) {
+				if (!xkd->cr3) {
 					uptr = (ulong *)(ptr + note->n_namesz);
 					uptr = (ulong *)roundup((ulong)uptr, 4);
-					nd->xen_kdump_data->cr3 = *uptr;
+					xkd->cr3 = *uptr;
 				}
 			} else {
-				nd->xen_kdump_data->flags |= KDUMP_MFN_LIST;
+				xkd->flags |= KDUMP_MFN_LIST;
 				uptr = (ulong *)(ptr + note->n_namesz);
 				uptr = (ulong *)roundup((ulong)uptr, 4);
 				words = note->n_descsz/sizeof(ulong);
 				/*
 				 *  If already set, overridden with --pfm_mfn
 				 */
-				if (!nd->xen_kdump_data->p2m_mfn)
-					nd->xen_kdump_data->p2m_mfn = *(uptr+(words-1));
-				if (words > 9 && !nd->xen_kdump_data->xen_phys_start)
-					nd->xen_kdump_data->xen_phys_start = *(uptr+(words-2));
-				nd->xen_kdump_data->xen_major_version = *uptr;
-				nd->xen_kdump_data->xen_minor_version = *(uptr+1);
+				if (!xkd->p2m_mfn)
+					xkd->p2m_mfn = *(uptr+(words-1));
+				if (words > 9 && !xkd->xen_phys_start)
+					xkd->xen_phys_start = *(uptr+(words-2));
+				xkd->xen_major_version = *uptr;
+				xkd->xen_minor_version = *(uptr+1);
 			}
 		}
 		break;
@@ -2316,36 +2272,36 @@ dump_Elf64_Nhdr(Elf64_Off offset, int store)
                 	netdump_print("(XEN_ELFNOTE_CRASH_INFO)\n");
 		xen_core = TRUE;
 		if (store) {
+			struct xen_kdump_data *xkd = get_xen_kdump_data();
 			pc->flags |= XEN_CORE;
-			nd->xen_kdump_data = &xen_kdump_data;
-			nd->xen_kdump_data->last_mfn_read = UNINITIALIZED;
-			nd->xen_kdump_data->last_pmd_read = UNINITIALIZED;
+			xkd->last_mfn_read = UNINITIALIZED;
+			xkd->last_pmd_read = UNINITIALIZED;
 
 			if ((note->n_type == NT_XEN_KDUMP_CR3) &&
 			    ((note->n_descsz/sizeof(ulong)) == 1)) {
-				nd->xen_kdump_data->flags |= KDUMP_CR3;
+				xkd->flags |= KDUMP_CR3;
 	                        /*
 	                         *  Use the first cr3 found.
 	                         */
-	                        if (!nd->xen_kdump_data->cr3) {
+	                        if (!xkd->cr3) {
 					up = (ulong *)(ptr + note->n_namesz);
 	                                up = (ulong *)roundup((ulong)up, 4);
-	                                nd->xen_kdump_data->cr3 = *up;
+	                                xkd->cr3 = *up;
 	                        }
 			} else {
-				nd->xen_kdump_data->flags |= KDUMP_MFN_LIST;
+				xkd->flags |= KDUMP_MFN_LIST;
 				up = (ulong *)(ptr + note->n_namesz);
 	                        up = (ulong *)roundup((ulong)up, 4);
 				words = note->n_descsz/sizeof(ulong);
 				/*
 				 *  If already set, overridden with --p2m_mfn
 				 */
-	                        if (!nd->xen_kdump_data->p2m_mfn)
-	                        	nd->xen_kdump_data->p2m_mfn = *(up+(words-1));
-				if (words > 9 && !nd->xen_kdump_data->xen_phys_start)
-					nd->xen_kdump_data->xen_phys_start = *(up+(words-2));
-				nd->xen_kdump_data->xen_major_version = *up;
-				nd->xen_kdump_data->xen_minor_version = *(up+1);
+	                        if (!xkd->p2m_mfn)
+					xkd->p2m_mfn = *(up+(words-1));
+				if (words > 9 && !xkd->xen_phys_start)
+					xkd->xen_phys_start = *(up+(words-2));
+				xkd->xen_major_version = *up;
+				xkd->xen_minor_version = *(up+1);
 			}
 		}
                 break;
@@ -3752,21 +3708,22 @@ read_kdump(int fd, void *bufptr, int cnt, ulong addr, physaddr_t paddr)
 	}
 
 	if (XEN_CORE_DUMPFILE() && !XEN_HYPER_MODE()) {
-	    	if (!(nd->xen_kdump_data->flags & KDUMP_P2M_INIT)) {
+		struct xen_kdump_data *xkd = get_xen_kdump_data();
+		if (!(xkd->flags & KDUMP_P2M_INIT)) {
         		if (!machdep->xen_kdump_p2m_create)
                 		error(FATAL,
                             "xen kdump dumpfiles not supported on this architecture\n");
 
-			if ((nd->xen_kdump_data->page = 
+			if ((xkd->page =
 			    (char *)malloc(PAGESIZE())) == NULL)
 				error(FATAL,
 				    "cannot malloc xen kdump data page\n");
 
-			if (!machdep->xen_kdump_p2m_create(nd->xen_kdump_data))
+			if (!machdep->xen_kdump_p2m_create(xkd))
                 		error(FATAL,
                     	    "cannot create xen kdump pfn-to-mfn mapping\n");
 
-        		nd->xen_kdump_data->flags |= KDUMP_P2M_INIT;
+			xkd->flags |= KDUMP_P2M_INIT;
 		}
 
 		if ((paddr = xen_kdump_p2m(paddr)) == P2M_FAILURE) {
@@ -3827,70 +3784,6 @@ kdump_memory_dump(FILE *fp)
 	return netdump_memory_dump(fp);
 }
 
-/*
- *  Translate a xen domain's pseudo-physical address into the
- *  xen machine address.  Since there's no compression involved,
- *  just the last phys_to_machine_mapping[] page read is cached, 
- *  which essentially caches 1024 p2m translations. 
- */
-static physaddr_t 
-xen_kdump_p2m(physaddr_t pseudo)
-{
-	ulong pfn, mfn_frame; 
-	ulong *mfnptr;
-	ulong mfn_idx, frame_idx;
-	physaddr_t paddr;
-	struct xen_kdump_data *xkd = nd->xen_kdump_data;
-
-	if (pc->curcmd_flags & XEN_MACHINE_ADDR)
-		return pseudo;
-
-#ifdef IA64
-	return ia64_xen_kdump_p2m(xkd, pseudo);
-#endif
-
-	xkd->accesses++;
-
-	pfn = (ulong)BTOP(pseudo);
-	mfn_idx = pfn / (PAGESIZE()/sizeof(ulong));
-	frame_idx = pfn % (PAGESIZE()/sizeof(ulong));
-	if (mfn_idx >= xkd->p2m_frames) {
-		if (CRASHDEBUG(8))
-			fprintf(fp, "xen_kdump_p2m: paddr/pfn: %llx/%lx: "
-			    "mfn_idx nonexistent\n",
-				(ulonglong)pseudo, pfn);
-		return P2M_FAILURE;
-	}
-	mfn_frame = xkd->p2m_mfn_frame_list[mfn_idx];
-
-	if (mfn_frame == xkd->last_mfn_read)
-		xkd->cache_hits++;
-	else {
-		if (CRASHDEBUG(8))
-			fprintf(fp, "xen_kdump_p2m: paddr/pfn: %llx/%lx: "
-			    "read mfn_frame: %llx\n",
-				(ulonglong)pseudo, pfn, PTOB(mfn_frame));
-		if (read_netdump(0, xkd->page, PAGESIZE(), 0, 
-		    (physaddr_t)PTOB(mfn_frame)) != PAGESIZE())
-			return P2M_FAILURE;
-	}
-
-	xkd->last_mfn_read = mfn_frame;
-
-	mfnptr = ((ulong *)(xkd->page)) + frame_idx;
-	paddr = (physaddr_t)PTOB((ulonglong)(*mfnptr));  
-	paddr |= PAGEOFFSET(pseudo);
-
-	if (CRASHDEBUG(7))
-		fprintf(fp, 
-		    "xen_kdump_p2m(%llx): mfn_idx: %ld frame_idx: %ld"
-		    " mfn_frame: %lx mfn: %lx => %llx\n",
-			(ulonglong)pseudo, mfn_idx, frame_idx, 
-			mfn_frame, *mfnptr, (ulonglong)paddr);
-	
-	return paddr;
-}
-
 struct vmcore_data *
 get_kdump_vmcore_data(void)
 {
@@ -3901,81 +3794,6 @@ get_kdump_vmcore_data(void)
 }
 
 /*
- *  Override the dom0 p2m mfn in the XEN_ELFNOTE_CRASH_INFO note
- *  in order to initiate a crash session of a guest kernel.
- */
-void
-xen_kdump_p2m_mfn(char *arg)
-{
-	ulong value;
-	int errflag;
-
-	errflag = 0;
-	value = htol(arg, RETURN_ON_ERROR|QUIET, &errflag);
-	if (!errflag) {
-		xen_kdump_data.p2m_mfn = value;
-		if (CRASHDEBUG(1))
-			error(INFO, 
-			    "xen_kdump_data.p2m_mfn override: %lx\n",  
-				value); 
-	} else 
-		error(WARNING, "invalid p2m_mfn argument: %s\n", arg);
-}
-
-/*
- *  Fujitsu dom0/HV sadump-generated dumpfile, which requires
- *  the --p2m_mfn command line argument.
- */
-int
-is_sadump_xen(void)
-{
-	if (xen_kdump_data.p2m_mfn) {
-		if (!XEN_CORE_DUMPFILE()) {
-			pc->flags |= XEN_CORE;
-			nd->xen_kdump_data = &xen_kdump_data;
-			nd->xen_kdump_data->last_mfn_read = UNINITIALIZED;
-			nd->xen_kdump_data->last_pmd_read = UNINITIALIZED;
-			nd->xen_kdump_data->flags |= KDUMP_MFN_LIST;
-		}
-		return TRUE;
-	}
-
-	return FALSE;
-}
-
-void
-set_xen_phys_start(char *arg)
-{
-	ulong value;
-	int errflag = 0;
-
-	value = htol(arg, RETURN_ON_ERROR|QUIET, &errflag);
-	if (!errflag)
-		xen_kdump_data.xen_phys_start = value;
-	else 
-		error(WARNING, "invalid xen_phys_start argument: %s\n", arg);
-}
-
-ulong
-xen_phys_start(void)
-{
-	return nd->xen_kdump_data->xen_phys_start;
-}
-
-int
-xen_major_version(void)
-{
-	return nd->xen_kdump_data->xen_major_version;
-}
-
-int
-xen_minor_version(void)
-{
-	return nd->xen_kdump_data->xen_minor_version;
-}
-
-
-/*
  *  The following set of functions are not used by the crash
  *  source code, but are available to extension modules for
  *  gathering register sets from ELF NT_PRSTATUS note sections.
diff --git a/netdump.h b/netdump.h
index adcfa34..b63eed7 100644
--- a/netdump.h
+++ b/netdump.h
@@ -68,7 +68,6 @@ struct vmcore_data {
 	ulong switch_stack;
 	uint num_prstatus_notes;
 	void *nt_prstatus_percpu[NR_CPUS];
-	struct xen_kdump_data *xen_kdump_data;
 	void *vmcoreinfo;
 	uint size_vmcoreinfo;
 /* Backup Region, first 640K of System RAM. */
@@ -83,58 +82,6 @@ struct vmcore_data {
 #define DUMP_ELF_INCOMPLETE  0x1   /* dumpfile is incomplete */
 
 /*
- *  ELF note types for Xen dom0/hypervisor kdumps.
- *  The comments below are from xen/include/public/elfnote.h.
- */
-
-/*
- * System information exported through crash notes.
- *
- * The kexec / kdump code will create one XEN_ELFNOTE_CRASH_INFO
- * note in case of a system crash. This note will contain various
- * information about the system, see xen/include/xen/elfcore.h.
- */
-#define XEN_ELFNOTE_CRASH_INFO 0x1000001
-
-/*
- * System registers exported through crash notes.
- *
- * The kexec / kdump code will create one XEN_ELFNOTE_CRASH_REGS
- * note per cpu in case of a system crash. This note is architecture
- * specific and will contain registers not saved in the "CORE" note.
- * See xen/include/xen/elfcore.h for more information.
- */
-#define XEN_ELFNOTE_CRASH_REGS 0x1000002
-
-
-/* 
- * For (temporary) backwards compatibility.
- */
-#define NT_XEN_KDUMP_CR3 0x10000001
-
-struct xen_kdump_data {
-	ulong flags;
-	ulong cr3;
-	ulong p2m_mfn;
-	char *page;
-	ulong last_mfn_read;
-	ulong last_pmd_read;
-	ulong cache_hits;
-	ulong accesses;
-	int p2m_frames;
-        ulong *p2m_mfn_frame_list;
-	ulong xen_phys_start;
-	int xen_major_version;
-	int xen_minor_version;
-};
-
-#define KDUMP_P2M_INIT  (0x1)
-#define KDUMP_CR3       (0x2)
-#define KDUMP_MFN_LIST  (0x4)
-
-#define P2M_FAILURE ((physaddr_t)(0xffffffffffffffffLL))
-
-/*
  * S390 CPU timer ELF note
  */
 #ifndef NT_S390_TIMER
diff --git a/x86.c b/x86.c
index 0abac90..f5a0275 100644
--- a/x86.c
+++ b/x86.c
@@ -4519,6 +4519,7 @@ xen_m2p_nonPAE(ulong machine)
 }
 
 #include "netdump.h"
+#include "xen_dom0.h"
 
 /*
  *  From the xen vmcore, create an index of mfns for each page that makes 
diff --git a/x86_64.c b/x86_64.c
index c209dcd..975354d 100644
--- a/x86_64.c
+++ b/x86_64.c
@@ -5726,6 +5726,7 @@ x86_64_irq_eframe_link(ulong stkref, struct bt_info *bt, FILE *ofp)
 }
 
 #include "netdump.h"
+#include "xen_dom0.h"
 
 /*
  *  From the xen vmcore, create an index of mfns for each page that makes
diff --git a/xen_dom0.c b/xen_dom0.c
new file mode 100644
index 0000000..547f3a1
--- /dev/null
+++ b/xen_dom0.c
@@ -0,0 +1,215 @@
+/* xen_dom0.c
+ *
+ * Copyright (C) 2015 David Anderson
+ * Copyright (C) 2015 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Author: David Anderson
+ */
+
+#include "defs.h"
+#include "xen_dom0.h"
+
+static struct xen_kdump_data xen_kdump_data = { 0 };
+static struct xen_kdump_data *xkd = &xen_kdump_data;
+
+void
+dump_xen_kdump_data(FILE *fp)
+{
+	int i, others;
+
+	fprintf(fp, "         xen_kdump_data: %s\n",
+		XEN_CORE_DUMPFILE() ? " " : "(unused)");
+	if (!XEN_CORE_DUMPFILE())
+		return;
+	fprintf(fp, "                    flags: %lx (", xkd->flags);
+	others = 0;
+	if (xkd->flags & KDUMP_P2M_INIT)
+		fprintf(fp, "%sKDUMP_P2M_INIT", others++ ? "|" : "");
+	if (xkd->flags & KDUMP_CR3)
+		fprintf(fp, "%sKDUMP_CR3", others++ ? "|" : "");
+	if (xkd->flags & KDUMP_MFN_LIST)
+		fprintf(fp, "%sKDUMP_MFN_LIST", others++ ? "|" : "");
+	fprintf(fp, ")\n");
+	fprintf(fp, "                  p2m_mfn: %lx\n",
+		xkd->p2m_mfn);
+	fprintf(fp, "                      cr3: %lx\n",
+		xkd->cr3);
+	fprintf(fp, "            last_mfn_read: %lx\n",
+		xkd->last_mfn_read);
+	fprintf(fp, "            last_pmd_read: %lx\n",
+		xkd->last_pmd_read);
+	fprintf(fp, "                     page: %lx\n",
+		xkd->page);
+	fprintf(fp, "                 accesses: %ld\n",
+		xkd->accesses);
+	fprintf(fp, "               cache_hits: %ld ",
+		xkd->cache_hits);
+	if (xkd->accesses)
+		fprintf(fp, "(%ld%%)",
+			xkd->cache_hits * 100 / xkd->accesses);
+	fprintf(fp, "\n               p2m_frames: %d\n",
+		xkd->p2m_frames);
+	fprintf(fp, "           xen_phys_start: %lx\n",
+		xkd->xen_phys_start);
+	fprintf(fp, "        xen_major_version: %d\n",
+		xkd->xen_major_version);
+	fprintf(fp, "        xen_minor_version: %d\n",
+		xkd->xen_minor_version);
+	fprintf(fp, "       p2m_mfn_frame_list: %lx\n",
+		xkd->p2m_mfn_frame_list);
+	for (i = 0; i < xkd->p2m_frames; i++)
+		fprintf(fp, "%lx ", xkd->p2m_mfn_frame_list[i]);
+	if (i) fprintf(fp, "\n");
+}
+
+/*
+ *  Override the dom0 p2m mfn in the XEN_ELFNOTE_CRASH_INFO note
+ *  in order to initiate a crash session of a guest kernel.
+ */
+void
+xen_kdump_p2m_mfn(char *arg)
+{
+	ulong value;
+	int errflag;
+
+	errflag = 0;
+	value = htol(arg, RETURN_ON_ERROR|QUIET, &errflag);
+	if (!errflag) {
+		xen_kdump_data.p2m_mfn = value;
+		if (CRASHDEBUG(1))
+			error(INFO,
+			    "xen_kdump_data.p2m_mfn override: %lx\n",
+				value);
+	} else
+		error(WARNING, "invalid p2m_mfn argument: %s\n", arg);
+}
+
+/*
+ *  Fujitsu dom0/HV sadump-generated dumpfile, which requires
+ *  the --p2m_mfn command line argument.
+ */
+int
+is_sadump_xen(void)
+{
+	if (xen_kdump_data.p2m_mfn) {
+		if (!XEN_CORE_DUMPFILE()) {
+			pc->flags |= XEN_CORE;
+			xkd->last_mfn_read = UNINITIALIZED;
+			xkd->last_pmd_read = UNINITIALIZED;
+			xkd->flags |= KDUMP_MFN_LIST;
+		}
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+void
+set_xen_phys_start(char *arg)
+{
+	ulong value;
+	int errflag = 0;
+
+	value = htol(arg, RETURN_ON_ERROR|QUIET, &errflag);
+	if (!errflag)
+		xen_kdump_data.xen_phys_start = value;
+	else
+		error(WARNING, "invalid xen_phys_start argument: %s\n", arg);
+}
+
+ulong
+xen_phys_start(void)
+{
+	return xkd->xen_phys_start;
+}
+
+int
+xen_major_version(void)
+{
+	return xkd->xen_major_version;
+}
+
+int
+xen_minor_version(void)
+{
+	return xkd->xen_minor_version;
+}
+
+struct xen_kdump_data *
+get_xen_kdump_data(void)
+{
+	return xkd;
+}
+
+/*
+ *  Translate a xen domain's pseudo-physical address into the
+ *  xen machine address.  Since there's no compression involved,
+ *  just the last phys_to_machine_mapping[] page read is cached,
+ *  which essentially caches 1024 p2m translations.
+ */
+physaddr_t
+xen_kdump_p2m(physaddr_t pseudo)
+{
+	ulong pfn, mfn_frame;
+	ulong *mfnptr;
+	ulong mfn_idx, frame_idx;
+	physaddr_t paddr;
+
+	if (pc->curcmd_flags & XEN_MACHINE_ADDR)
+		return pseudo;
+
+#ifdef IA64
+	return ia64_xen_kdump_p2m(xkd, pseudo);
+#endif
+
+	xkd->accesses++;
+
+	pfn = (ulong)BTOP(pseudo);
+	mfn_idx = pfn / (PAGESIZE()/sizeof(ulong));
+	frame_idx = pfn % (PAGESIZE()/sizeof(ulong));
+	if (mfn_idx >= xkd->p2m_frames) {
+		if (CRASHDEBUG(8))
+			fprintf(fp, "xen_kdump_p2m: paddr/pfn: %llx/%lx: "
+			    "mfn_idx nonexistent\n",
+				(ulonglong)pseudo, pfn);
+		return P2M_FAILURE;
+	}
+	mfn_frame = xkd->p2m_mfn_frame_list[mfn_idx];
+
+	if (mfn_frame == xkd->last_mfn_read)
+		xkd->cache_hits++;
+	else {
+		if (CRASHDEBUG(8))
+			fprintf(fp, "xen_kdump_p2m: paddr/pfn: %llx/%lx: "
+			    "read mfn_frame: %llx\n",
+				(ulonglong)pseudo, pfn, PTOB(mfn_frame));
+		if (read_netdump(0, xkd->page, PAGESIZE(), 0,
+		    (physaddr_t)PTOB(mfn_frame)) != PAGESIZE())
+			return P2M_FAILURE;
+	}
+
+	xkd->last_mfn_read = mfn_frame;
+
+	mfnptr = ((ulong *)(xkd->page)) + frame_idx;
+	paddr = (physaddr_t)PTOB((ulonglong)(*mfnptr));
+	paddr |= PAGEOFFSET(pseudo);
+
+	if (CRASHDEBUG(7))
+		fprintf(fp,
+		    "xen_kdump_p2m(%llx): mfn_idx: %ld frame_idx: %ld"
+		    " mfn_frame: %lx mfn: %lx => %llx\n",
+			(ulonglong)pseudo, mfn_idx, frame_idx,
+			mfn_frame, *mfnptr, (ulonglong)paddr);
+
+	return paddr;
+}
diff --git a/xen_dom0.h b/xen_dom0.h
new file mode 100644
index 0000000..a8a563d
--- /dev/null
+++ b/xen_dom0.h
@@ -0,0 +1,74 @@
+/* xen_dom0.h
+ *
+ * Copyright (C) 2015 David Anderson
+ * Copyright (C) 2015 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Author: David Anderson
+ */
+
+/*
+ *  ELF note types for Xen dom0/hypervisor kdumps.
+ *  The comments below are from xen/include/public/elfnote.h.
+ */
+
+/*
+ * System information exported through crash notes.
+ *
+ * The kexec / kdump code will create one XEN_ELFNOTE_CRASH_INFO
+ * note in case of a system crash. This note will contain various
+ * information about the system, see xen/include/xen/elfcore.h.
+ */
+#define XEN_ELFNOTE_CRASH_INFO 0x1000001
+
+/*
+ * System registers exported through crash notes.
+ *
+ * The kexec / kdump code will create one XEN_ELFNOTE_CRASH_REGS
+ * note per cpu in case of a system crash. This note is architecture
+ * specific and will contain registers not saved in the "CORE" note.
+ * See xen/include/xen/elfcore.h for more information.
+ */
+#define XEN_ELFNOTE_CRASH_REGS 0x1000002
+
+
+/*
+ * For (temporary) backwards compatibility.
+ */
+#define NT_XEN_KDUMP_CR3 0x10000001
+
+struct xen_kdump_data {
+	ulong flags;
+	ulong cr3;
+	ulong p2m_mfn;
+	char *page;
+	ulong last_mfn_read;
+	ulong last_pmd_read;
+	ulong cache_hits;
+	ulong accesses;
+	int p2m_frames;
+        ulong *p2m_mfn_frame_list;
+	ulong xen_phys_start;
+	int xen_major_version;
+	int xen_minor_version;
+};
+
+#define KDUMP_P2M_INIT  (0x1)
+#define KDUMP_CR3       (0x2)
+#define KDUMP_MFN_LIST  (0x4)
+
+#define P2M_FAILURE ((physaddr_t)(0xffffffffffffffffLL))
+
+void dump_xen_kdump_data(FILE *);
+struct xen_kdump_data *get_xen_kdump_data(void);
+
+physaddr_t xen_kdump_p2m(physaddr_t);
-- 
2.1.4




More information about the Crash-utility mailing list