[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] [XEN] Restore backwards compatibility by supporting __xen_guest



# HG changeset patch
# User Ian Campbell <ian.campbell@xxxxxxxxxxxxx>
# Node ID 2eb8efcc70d1744198d729e1caf2a59b046b178b
# Parent  cc006f78cbe20d0b84f7e80c2b1fac6c9eb7dc29
[XEN] Restore backwards compatibility by supporting __xen_guest
section in dom0 loader.

Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxxxxx>
---
 xen/arch/x86/domain_build.c |   13 ---
 xen/common/elf.c            |  163 ++++++++++++++++++++++++++++++++++++++++----
 xen/include/xen/sched.h     |   13 +++
 3 files changed, 166 insertions(+), 23 deletions(-)

diff -r cc006f78cbe2 -r 2eb8efcc70d1 xen/arch/x86/domain_build.c
--- a/xen/arch/x86/domain_build.c       Wed Aug 23 18:35:21 2006 +0100
+++ b/xen/arch/x86/domain_build.c       Wed Aug 23 18:38:49 2006 +0100
@@ -290,14 +290,7 @@ int construct_dom0(struct domain *d,
     if ( (rc = parseelfimage(&dsi)) != 0 )
         return rc;
 
-    if ( dsi.__elfnote_section == NULL )
-    {
-        printk("Not a Xen-ELF image: no Xen ELF notes were found.\n");
-        return -EINVAL;
-    }
-
-    p = xen_elfnote_string(&dsi, XEN_ELFNOTE_PAE_MODE);
-    dom0_pae = !!(p != NULL && strcmp(p, "yes") == 0);
+    dom0_pae = (dsi.pae_kernel != PAEKERN_no);
     xen_pae  = (CONFIG_PAGING_LEVELS == 3);
     if ( dom0_pae != xen_pae )
     {
@@ -306,8 +299,8 @@ int construct_dom0(struct domain *d,
         return -EINVAL;
     }
 
-    if ( xen_pae )
-        set_bit(VMASST_TYPE_pae_extended_cr3, &d->vm_assist);
+    if ( xen_pae && dsi.pae_kernel == PAEKERN_extended_cr3 )
+            set_bit(VMASST_TYPE_pae_extended_cr3, &d->vm_assist);
 
     if ( (p = xen_elfnote_string(&dsi, XEN_ELFNOTE_FEATURES)) != NULL )
     {
diff -r cc006f78cbe2 -r 2eb8efcc70d1 xen/common/elf.c
--- a/xen/common/elf.c  Wed Aug 23 18:35:21 2006 +0100
+++ b/xen/common/elf.c  Wed Aug 23 18:38:49 2006 +0100
@@ -23,6 +23,80 @@ static inline int is_loadable_phdr(Elf_P
 }
 
 /*
+ * Fallback for kernels containing only the legacy __xen_guest string
+ * and no ELF notes.
+ */
+static int is_xen_guest_section(Elf_Shdr *shdr, const char *shstrtab)
+{
+    return strcmp(&shstrtab[shdr->sh_name], "__xen_guest") == 0;
+}
+
+static const char *xen_guest_lookup(struct domain_setup_info *dsi, int type)
+{
+    const char *xenguest_fallbacks[] = {
+        [XEN_ELFNOTE_ENTRY] = "VIRT_ENTRY=",
+        [XEN_ELFNOTE_HYPERCALL_PAGE] = "HYPERCALL_PAGE=",
+        [XEN_ELFNOTE_VIRT_BASE] = "VIRT_BASE=",
+        [XEN_ELFNOTE_PADDR_OFFSET] = "ELF_PADDR_OFFSET=",
+        [XEN_ELFNOTE_XEN_VERSION] = "XEN_VER=",
+        [XEN_ELFNOTE_GUEST_OS] = "GUEST_OS=",
+        [XEN_ELFNOTE_GUEST_VERSION] = "GUEST_VER=",
+        [XEN_ELFNOTE_LOADER] = "LOADER=",
+        [XEN_ELFNOTE_PAE_MODE] = "PAE=",
+        [XEN_ELFNOTE_FEATURES] = "FEATURES=",
+        [XEN_ELFNOTE_BSD_SYMTAB] = "BSD_SYMTAB=",
+    };
+    const char *fallback;
+    const char *p;
+
+    if ( type > sizeof(xenguest_fallbacks) )
+        return NULL;
+
+    if ( (fallback = xenguest_fallbacks[type]) == NULL )
+        return NULL;
+
+    if ( (p = strstr(dsi->__xen_guest_string,fallback)) == NULL )
+        return NULL;
+
+    return p + strlen(fallback);
+}
+
+static const char *xen_guest_string(struct domain_setup_info *dsi, int type)
+{
+    const char *p = xen_guest_lookup(dsi, type);
+
+    /*
+     * We special case this since the __xen_guest_section treats the
+     * mere precense of the BSD_SYMTAB string as true or false.
+     */
+    if ( type == XEN_ELFNOTE_BSD_SYMTAB )
+        return p ? "yes" : "no";
+
+    return p;
+}
+
+static unsigned long long xen_guest_numeric(struct domain_setup_info *dsi,
+                                                   int type, int *defined)
+{
+    const char *p = xen_guest_lookup(dsi, type);
+    unsigned long long value;
+
+    if ( p == NULL )
+        return 0;
+
+    value = simple_strtoull(p, NULL, 0);
+
+    /* We special case this since __xen_guest_section contains a PFN
+     * for this field not a virtual address.
+     */
+    if (type == XEN_ELFNOTE_HYPERCALL_PAGE)
+        value = dsi->v_start + (value<<PAGE_SHIFT);
+
+    *defined = 1;
+    return value;
+}
+
+/*
  * Interface to the Xen ELF notes.
  */
 #define ELFNOTE_NAME(_n_)   ((void*)(_n_) + sizeof(*(_n_)))
@@ -65,21 +139,20 @@ static Elf_Note *xen_elfnote_lookup(stru
             return note;
     }
 
-    DPRINTK("unable to find Xen ELF note with type %#x\n", type);
     return NULL;
 }
 
 const char *xen_elfnote_string(struct domain_setup_info *dsi, int type)
 {
     Elf_Note *note;
+
+    if ( !dsi->__elfnote_section )
+        return xen_guest_string(dsi, type);
 
     note = xen_elfnote_lookup(dsi, type);
     if ( note == NULL )
         return NULL;
 
-    DPRINTK("found Xen ELF note type %#x = \"%s\"\n",
-            type, (char *)ELFNOTE_DESC(note));
-
     return (const char *)ELFNOTE_DESC(note);
 }
 
@@ -89,6 +162,9 @@ unsigned long long xen_elfnote_numeric(s
     Elf_Note *note;
 
     *defined = 0;
+
+    if ( !dsi->__elfnote_section )
+        return xen_guest_numeric(dsi, type, defined);
 
     note = xen_elfnote_lookup(dsi, type);
     if ( note == NULL )
@@ -105,6 +181,8 @@ unsigned long long xen_elfnote_numeric(s
         *defined = 1;
         return *(uint64_t*)ELFNOTE_DESC(note);
     default:
+        printk("ERROR: unknown data size %#x for numeric type note %#x\n",
+               note->descsz, type);
         return 0;
     }
 }
@@ -146,6 +224,7 @@ int parseelfimage(struct domain_setup_in
     shstrtab = image + shdr->sh_offset;
 
     dsi->__elfnote_section = NULL;
+    dsi->__xen_guest_string = NULL;
 
     /* Look for .notes segment containing at least one Xen note */
     for ( h = 0; h < ehdr->e_shnum; h++ )
@@ -159,25 +238,71 @@ int parseelfimage(struct domain_setup_in
         break;
     }
 
-    /* Check the contents of the Xen notes. */
-    if ( dsi->__elfnote_section )
+    /* Fall back to looking for the special '__xen_guest' section. */
+    if ( dsi->__elfnote_section == NULL )
+    {
+        for ( h = 0; h < ehdr->e_shnum; h++ )
+        {
+            shdr = (Elf_Shdr *)(image + ehdr->e_shoff + (h*ehdr->e_shentsize));
+            if ( is_xen_guest_section(shdr, shstrtab) )
+            {
+                dsi->__xen_guest_string = (char *)image + shdr->sh_offset;
+                break;
+            }
+        }
+    }
+
+    /* Check the contents of the Xen notes or guest string. */
+    if ( dsi->__elfnote_section || dsi->__xen_guest_string )
     {
         const char *loader = xen_elfnote_string(dsi, XEN_ELFNOTE_LOADER);
         const char *guest_os = xen_elfnote_string(dsi, XEN_ELFNOTE_GUEST_OS);
         const char *xen_version =
             xen_elfnote_string(dsi, XEN_ELFNOTE_XEN_VERSION);
 
-        if ( ( loader == NULL || strcmp(loader, "generic") ) &&
-             ( guest_os == NULL || strcmp(guest_os, "linux") ) )
+        if ( ( loader == NULL || strncmp(loader, "generic", 7) ) &&
+             ( guest_os == NULL || strncmp(guest_os, "linux", 5) ) )
         {
             printk("ERROR: Will only load images built for the generic "
                    "loader or Linux images");
             return -EINVAL;
         }
 
-        if ( xen_version == NULL || strcmp(xen_version, "xen-3.0") )
+        if ( xen_version == NULL || strncmp(xen_version, "xen-3.0", 7) )
         {
             printk("ERROR: Xen will only load images built for Xen v3.0\n");
+        }
+    }
+    else
+    {
+#if defined(__x86_64__) || defined(__i386__)
+        printk("ERROR: Not a Xen-ELF image: "
+               "No ELF notes or '__xen_guest' section found.\n");
+        return -EINVAL;
+#endif
+    }
+
+    /*
+     * If we have ELF notes then PAE=yes implies that we must support
+     * the extended cr3 syntax. Otherwise we need to find the
+     * [extended-cr3] syntax in the __xen_guest string.
+     */
+    dsi->pae_kernel = PAEKERN_no;
+    if ( dsi->__elfnote_section )
+    {
+        p = xen_elfnote_string(dsi, XEN_ELFNOTE_PAE_MODE);
+        if ( p != NULL && strncmp(p, "yes", 3) == 0 )
+            dsi->pae_kernel = PAEKERN_extended_cr3;
+
+    }
+    else
+    {
+        p = xen_guest_lookup(dsi, XEN_ELFNOTE_PAE_MODE);
+        if ( p != NULL && strncmp(p, "yes", 3) == 0 )
+        {
+            dsi->pae_kernel = PAEKERN_yes;
+            if ( !strncmp(p+4, "[extended-cr3]", 14) )
+                dsi->pae_kernel = PAEKERN_extended_cr3;
         }
     }
 
@@ -187,11 +312,24 @@ int parseelfimage(struct domain_setup_in
     if ( !virt_base_defined )
         dsi->v_start = 0;
 
-    /* We are using the ELF notes interface so the default is 0. */
+    /*
+     * If we are using the legacy __xen_guest section then elf_pa_off
+     * defaults to v_start in order to maintain compatibility with
+     * older hypervisors which set padd in the ELF header to
+     * virt_base.
+     *
+     * If we are using the modern ELF notes interface then the default
+     * is 0.
+     */
     dsi->elf_paddr_offset =
         xen_elfnote_numeric(dsi, XEN_ELFNOTE_PADDR_OFFSET, 
&elf_pa_off_defined);
     if ( !elf_pa_off_defined )
-        dsi->elf_paddr_offset = 0;
+    {
+        if ( dsi->__elfnote_section )
+            dsi->elf_paddr_offset = 0;
+        else
+            dsi->elf_paddr_offset = dsi->v_start;
+    }
 
     if ( elf_pa_off_defined && !virt_base_defined )
     {
@@ -219,6 +357,7 @@ int parseelfimage(struct domain_setup_in
     }
 
     dsi->v_kernentry = ehdr->e_entry;
+
     virt_entry =
         xen_elfnote_numeric(dsi, XEN_ELFNOTE_ENTRY, &virt_entry_defined);
     if ( virt_entry_defined )
@@ -234,7 +373,7 @@ int parseelfimage(struct domain_setup_in
     }
 
     p = xen_elfnote_string(dsi, XEN_ELFNOTE_BSD_SYMTAB);
-    if ( p != NULL && strcmp(p, "yes") == 0 )
+    if ( p != NULL && strncmp(p, "yes", 3) == 0 )
         dsi->load_symtab = 1;
 
     dsi->v_kernstart = kernstart;
diff -r cc006f78cbe2 -r 2eb8efcc70d1 xen/include/xen/sched.h
--- a/xen/include/xen/sched.h   Wed Aug 23 18:35:21 2006 +0100
+++ b/xen/include/xen/sched.h   Wed Aug 23 18:38:49 2006 +0100
@@ -179,13 +179,24 @@ struct domain_setup_info
     unsigned long v_kernstart;
     unsigned long v_kernend;
     unsigned long v_kernentry;
+#define PAEKERN_no           0
+#define PAEKERN_yes          1
+#define PAEKERN_extended_cr3 2
+    unsigned int  pae_kernel;
     /* Initialised by loader: Private. */
     unsigned long elf_paddr_offset;
     unsigned int  load_symtab;
     unsigned long symtab_addr;
     unsigned long symtab_len;
-    /* Indicate whether it's xen specific image */
+    /*
+     * Only one of __elfnote_* or __xen_guest_string will be
+     * non-NULL.
+     *
+     * You should use the xen_elfnote_* accessors below in order to
+     * pickup the correct one and retain backwards compatibility.
+     */
     void *__elfnote_section, *__elfnote_section_end;
+    char *__xen_guest_string;
 };
 
 extern struct vcpu *idle_vcpu[NR_CPUS];

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.