diff mbox

xen: Add support for dom0 with Linux kernel 3.19 and newer

Message ID 1453407231-25432-1-git-send-email-daniel.kiper@oracle.com
State New, archived
Headers show

Commit Message

Daniel Kiper Jan. 21, 2016, 8:13 p.m. UTC
Linux kernel commit 054954eb051f35e74b75a566a96fe756015352c8
(xen: switch to linear virtual mapped sparse p2m list), which
appeared in 3.19, introduced linear virtual mapped sparse p2m
list. If readmem() reads p2m then it access this list using
physical addresses. Sadly, VMA to physical address translation
in crash requires access to p2m list. This means that we have
a chicken and egg problem. In general this issue must be solved
by introducing some changes in libxl, Linux kernel and crash
(I have added this task to my long TODO list). However, in dom0
case we can use crash_xen_info_t.dom0_pfn_to_mfn_frame_list_list
which is available out of the box. So, let's use it and make
at least some users happy.

Signed-off-by: Daniel Kiper <daniel.kiper@oracle.com>
---
 kernel.c   |   81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------
 xen_dom0.c |    3 ++-
 xen_dom0.h |    2 ++
 3 files changed, 77 insertions(+), 9 deletions(-)

Comments

David Vrabel Jan. 22, 2016, 10:03 a.m. UTC | #1
On 21/01/16 20:13, Daniel Kiper wrote:
> Linux kernel commit 054954eb051f35e74b75a566a96fe756015352c8
> (xen: switch to linear virtual mapped sparse p2m list), which
> appeared in 3.19, introduced linear virtual mapped sparse p2m
> list. If readmem() reads p2m then it access this list using
> physical addresses. Sadly, VMA to physical address translation
> in crash requires access to p2m list. This means that we have
> a chicken and egg problem. In general this issue must be solved
> by introducing some changes in libxl, Linux kernel and crash
> (I have added this task to my long TODO list). However, in dom0
> case we can use crash_xen_info_t.dom0_pfn_to_mfn_frame_list_list
> which is available out of the box. So, let's use it and make
> at least some users happy.

I'm confused.  How does a virtual address to (pseudo-)physical address
lookup require access to the p2m?  Surely this is a walk of the page
tables followed by a M2P lookup on the MFN in the L1 PTE?

David
Daniel Kiper Jan. 22, 2016, 2:22 p.m. UTC | #2
On Fri, Jan 22, 2016 at 10:03:34AM +0000, David Vrabel wrote:
> On 21/01/16 20:13, Daniel Kiper wrote:
> > Linux kernel commit 054954eb051f35e74b75a566a96fe756015352c8
> > (xen: switch to linear virtual mapped sparse p2m list), which
> > appeared in 3.19, introduced linear virtual mapped sparse p2m
> > list. If readmem() reads p2m then it access this list using
> > physical addresses. Sadly, VMA to physical address translation
> > in crash requires access to p2m list. This means that we have
> > a chicken and egg problem. In general this issue must be solved
> > by introducing some changes in libxl, Linux kernel and crash
> > (I have added this task to my long TODO list). However, in dom0
> > case we can use crash_xen_info_t.dom0_pfn_to_mfn_frame_list_list
> > which is available out of the box. So, let's use it and make
> > at least some users happy.
>
> I'm confused.  How does a virtual address to (pseudo-)physical address
> lookup require access to the p2m?  Surely this is a walk of the page
> tables followed by a M2P lookup on the MFN in the L1 PTE?

Correct but crash does it a bit backward and scans p2m. I am not sure way,
however, I am going to look at it during work on PV guests support.

Daniel
diff mbox

Patch

diff --git a/kernel.c b/kernel.c
index 5ce2fb9..b07149e 100644
--- a/kernel.c
+++ b/kernel.c
@@ -17,6 +17,7 @@ 
 
 #include "defs.h"
 #include "xen_hyper_defs.h"
+#include "xen_dom0.h"
 #include <elf.h>
 #include <libgen.h>
 #include <ctype.h>
@@ -61,6 +62,7 @@  static int restore_stack(struct bt_info *);
 static ulong __xen_m2p(ulonglong, ulong);
 static ulong __xen_pvops_m2p_l2(ulonglong, ulong);
 static ulong __xen_pvops_m2p_l3(ulonglong, ulong);
+static ulong __xen_pvops_m2p_hyper(ulonglong, ulong);
 static int search_mapping_page(ulong, ulong *, ulong *, ulong *);
 static void read_in_kernel_config_err(int, char *);
 static void BUG_bytes_init(void);
@@ -175,6 +177,9 @@  kernel_init()
 						&kt->pvops_xen.p2m_mid_missing);
 			get_symbol_data("p2m_missing", sizeof(ulong),
 						&kt->pvops_xen.p2m_missing);
+		} else if (symbol_exists("xen_p2m_addr")) {
+			if (!XEN_CORE_DUMPFILE())
+				error(FATAL, "p2m array in new format is unreadable.");
 		} else {
 			kt->pvops_xen.p2m_top_entries = get_array_length("p2m_top", NULL, 0);
 			kt->pvops_xen.p2m_top = symbol_value("p2m_top");
@@ -5850,12 +5855,14 @@  no_cpu_flags:
 	else
 		fprintf(fp, "\n");
 
-	fprintf(fp, "              pvops_xen:\n");
-	fprintf(fp, "                    p2m_top: %lx\n", kt->pvops_xen.p2m_top);
-	fprintf(fp, "            p2m_top_entries: %d\n", kt->pvops_xen.p2m_top_entries);
-	if (symbol_exists("p2m_mid_missing"))
-		fprintf(fp, "            p2m_mid_missing: %lx\n", kt->pvops_xen.p2m_mid_missing);
-	fprintf(fp, "                p2m_missing: %lx\n", kt->pvops_xen.p2m_missing);
+	if (!symbol_exists("xen_p2m_addr")) {
+		fprintf(fp, "              pvops_xen:\n");
+		fprintf(fp, "                    p2m_top: %lx\n", kt->pvops_xen.p2m_top);
+		fprintf(fp, "            p2m_top_entries: %d\n", kt->pvops_xen.p2m_top_entries);
+		if (symbol_exists("p2m_mid_missing"))
+			fprintf(fp, "            p2m_mid_missing: %lx\n", kt->pvops_xen.p2m_mid_missing);
+		fprintf(fp, "                p2m_missing: %lx\n", kt->pvops_xen.p2m_missing);
+	}
 }
 
 /*
@@ -8873,6 +8880,12 @@  __xen_m2p(ulonglong machine, ulong mfn)
 	ulong c, i, kmfn, mapping, p, pfn;
 	ulong start, end;
 	ulong *mp = (ulong *)kt->m2p_page;
+	int memtype;
+
+	if (XEN_CORE_DUMPFILE() && symbol_exists("xen_p2m_addr"))
+		memtype = PHYSADDR;
+	else
+		memtype = KVADDR;
 
 	/*
 	 *  Check the FIFO cache first.
@@ -8883,13 +8896,19 @@  __xen_m2p(ulonglong machine, ulong mfn)
 		     (mfn <= kt->p2m_mapping_cache[c].end))) { 
 
 			if (kt->p2m_mapping_cache[c].mapping != kt->last_mapping_read) {
-                        	if (!readmem(kt->p2m_mapping_cache[c].mapping, KVADDR, 
+				if (memtype == PHYSADDR)
+					pc->curcmd_flags |= XEN_MACHINE_ADDR;
+
+				if (!readmem(kt->p2m_mapping_cache[c].mapping, memtype,
 			       	    mp, PAGESIZE(), "phys_to_machine_mapping page (cached)", 
 			    	    RETURN_ON_ERROR))
                                 	error(FATAL, "cannot access "
                                     	    "phys_to_machine_mapping page\n");
 				else
 					kt->last_mapping_read = kt->p2m_mapping_cache[c].mapping;
+
+				if (memtype == PHYSADDR)
+					pc->curcmd_flags &= ~XEN_MACHINE_ADDR;
 			} else
 				kt->p2m_page_cache_hits++;
 
@@ -8919,11 +8938,13 @@  __xen_m2p(ulonglong machine, ulong mfn)
 	if (PVOPS_XEN()) {
 		/*
 		 *  The machine address was not cached, so search from the
-		 *  beginning of the p2m_top array, caching the contiguous
+		 *  beginning of the p2m tree/array, caching the contiguous
 		 *  range containing the found machine address.
 		 */
 		if (symbol_exists("p2m_mid_missing"))
 			pfn = __xen_pvops_m2p_l3(machine, mfn);
+		else if (symbol_exists("xen_p2m_addr"))
+			pfn = __xen_pvops_m2p_hyper(machine, mfn);
 		else
 			pfn = __xen_pvops_m2p_l2(machine, mfn);
 
@@ -9088,6 +9109,50 @@  __xen_pvops_m2p_l3(ulonglong machine, ulong mfn)
 	return XEN_MFN_NOT_FOUND;
 }
 
+static ulong
+__xen_pvops_m2p_hyper(ulonglong machine, ulong mfn)
+{
+	ulong c, end, i, mapping, p, pfn, start;
+
+	for (p = 0;
+	     p < xkd->p2m_frames;
+	     ++p) {
+
+		mapping = PTOB(xkd->p2m_mfn_frame_list[p]);
+
+		if (mapping != kt->last_mapping_read) {
+			pc->curcmd_flags |= XEN_MACHINE_ADDR;
+			if (!readmem(mapping, PHYSADDR, (void *)kt->m2p_page,
+					PAGESIZE(), "p2m_mfn_frame_list page", RETURN_ON_ERROR))
+				error(FATAL, "cannot access p2m_mfn_frame_list[] page\n");
+
+			pc->curcmd_flags &= ~XEN_MACHINE_ADDR;
+			kt->last_mapping_read = mapping;
+		}
+
+		kt->p2m_pages_searched++;
+
+		if (search_mapping_page(mfn, &i, &start, &end)) {
+			pfn = p * XEN_PFNS_PER_PAGE + i;
+			if (CRASHDEBUG(1))
+			    console("pages: %d mfn: %lx (%llx) p: %ld"
+				" i: %ld pfn: %lx (%llx)\n", p + 1, mfn, machine,
+				p, i, pfn, XEN_PFN_TO_PSEUDO(pfn));
+
+			c = kt->p2m_cache_index;
+			kt->p2m_mapping_cache[c].start = start;
+			kt->p2m_mapping_cache[c].end = end;
+			kt->p2m_mapping_cache[c].mapping = mapping;
+			kt->p2m_mapping_cache[c].pfn = p * XEN_PFNS_PER_PAGE;
+			kt->p2m_cache_index = (c+1) % P2M_MAPPING_CACHE;
+
+			return pfn;
+		}
+	}
+
+	return XEN_MFN_NOT_FOUND;
+}
+
 /*
  *  Search for an mfn in the current mapping page, and if found, 
  *  determine the range of contiguous mfns that it's contained
diff --git a/xen_dom0.c b/xen_dom0.c
index 6abb443..6770fd4 100644
--- a/xen_dom0.c
+++ b/xen_dom0.c
@@ -20,7 +20,8 @@ 
 #include "xen_dom0.h"
 
 static struct xen_kdump_data xen_kdump_data = { 0 };
-static struct xen_kdump_data *xkd = &xen_kdump_data;
+
+struct xen_kdump_data *xkd = &xen_kdump_data;
 
 void
 dump_xen_kdump_data(FILE *fp)
diff --git a/xen_dom0.h b/xen_dom0.h
index 4f0ff53..963c75c 100644
--- a/xen_dom0.h
+++ b/xen_dom0.h
@@ -68,6 +68,8 @@  struct xen_kdump_data {
 
 #define P2M_FAILURE ((physaddr_t)(0xffffffffffffffffLL))
 
+extern struct xen_kdump_data *xkd;
+
 void dump_xen_kdump_data(FILE *);
 struct xen_kdump_data *get_xen_kdump_data(void);