# 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
|