WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

[Xen-devel] [PATCH] Elf loader fixes

To: Xen devel list <xen-devel@xxxxxxxxxxxxxxxxxxx>
Subject: [Xen-devel] [PATCH] Elf loader fixes
From: Gerd Hoffmann <kraxel@xxxxxxx>
Date: Wed, 22 Feb 2006 12:37:26 +0100
Delivery-date: Wed, 22 Feb 2006 11:50:31 +0000
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: Thunderbird 1.5 (X11/20060111)
  Hi folks,

The Xen ELF kernel loader is quite quirky wrt. physical and virtual
addresses, probably for historical reasons, linux got that wrong too
until very recently (kexec merge in 2.6.14 or so).  The patch below
fixes that.

Changes:
  * Fix linux kernel ELF entry point (also submitted to lkml)
  * Drop LOAD_OFFSET re-#define hack in xen headers.
  * Fix both dom0 and libxc elf loaders.
  * add quick mode so loading old linux kernels doesn't break.

Linux-wise everything should be OK with that, but it might break other
OS'es which also use the ELF loader (in case they create bug-compatible
ELF headers with broken paddr entries ...).

please apply,

  Gerd

diff -r 5abf652c4c52 linux-2.6-xen-sparse/arch/i386/kernel/vmlinux.lds.S
--- a/linux-2.6-xen-sparse/arch/i386/kernel/vmlinux.lds.S       Tue Feb 21 
18:36:00 2006
+++ b/linux-2.6-xen-sparse/arch/i386/kernel/vmlinux.lds.S       Wed Feb 22 
12:20:06 2006
@@ -10,7 +10,7 @@
 
 OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
 OUTPUT_ARCH(i386)
-ENTRY(phys_startup_32)
+ENTRY(startup_32)
 jiffies = jiffies_64;
 SECTIONS
 {
diff -r 5abf652c4c52 linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/page.h
--- a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/page.h Tue Feb 21 
18:36:00 2006
+++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/page.h Wed Feb 22 
12:20:06 2006
@@ -288,10 +288,6 @@
 #endif
 #define __KERNEL_START         (__PAGE_OFFSET + __PHYSICAL_START)
 
-#undef LOAD_OFFSET
-#define LOAD_OFFSET            0
-
-
 #define PAGE_OFFSET            ((unsigned long)__PAGE_OFFSET)
 #define VMALLOC_RESERVE                ((unsigned long)__VMALLOC_RESERVE)
 #define MAXMEM                 
(HYPERVISOR_VIRT_START-__PAGE_OFFSET-__VMALLOC_RESERVE)
diff -r 5abf652c4c52 tools/libxc/xc_load_elf.c
--- a/tools/libxc/xc_load_elf.c Tue Feb 21 18:36:00 2006
+++ b/tools/libxc/xc_load_elf.c Wed Feb 22 12:20:06 2006
@@ -138,10 +138,10 @@
         phdr = (Elf_Phdr *)(image + ehdr->e_phoff + (h*ehdr->e_phentsize));
         if ( !is_loadable_phdr(phdr) )
             continue;
-        if ( phdr->p_paddr < kernstart )
-            kernstart = phdr->p_paddr;
-        if ( (phdr->p_paddr + phdr->p_memsz) > kernend )
-            kernend = phdr->p_paddr + phdr->p_memsz;
+        if ( phdr->p_vaddr < kernstart )
+            kernstart = phdr->p_vaddr;
+        if ( (phdr->p_vaddr + phdr->p_memsz) > kernend )
+            kernend = phdr->p_vaddr + phdr->p_memsz;
     }
 
     if ( (kernstart > kernend) || 
@@ -189,7 +189,18 @@
         
         for ( done = 0; done < phdr->p_filesz; done += chunksz )
         {
-            pa = (phdr->p_paddr + done) - dsi->v_start;
+            if (phdr->p_paddr == phdr->p_vaddr) {
+                /*
+                 * Bug compatibility alert: In older linux kernels
+                 * p_paddr is broken, it doesn't contain the physical
+                 * address but instead is identical to p_vaddr.  Thus
+                 * we can't use it directly, instead we'll guess it
+                 * using dsi->v_start.
+                 */
+                pa = (phdr->p_vaddr + done) - dsi->v_start;
+            } else {
+                pa = (phdr->p_paddr + done);
+            }
             va = xc_map_foreign_range(
                 xch, dom, PAGE_SIZE, PROT_WRITE, parray[pa>>PAGE_SHIFT]);
             chunksz = phdr->p_filesz - done;
@@ -202,7 +213,12 @@
 
         for ( ; done < phdr->p_memsz; done += chunksz )
         {
-            pa = (phdr->p_paddr + done) - dsi->v_start;
+            if (phdr->p_paddr == phdr->p_vaddr) {
+                /* bug compatibility alert, see above */
+                pa = (phdr->p_vaddr + done) - dsi->v_start;
+            } else {
+                pa = (phdr->p_paddr + done);
+            }
             va = xc_map_foreign_range(
                 xch, dom, PAGE_SIZE, PROT_WRITE, parray[pa>>PAGE_SHIFT]);
             chunksz = phdr->p_memsz - done;
diff -r 5abf652c4c52 xen/arch/x86/domain.c
--- a/xen/arch/x86/domain.c     Tue Feb 21 18:36:00 2006
+++ b/xen/arch/x86/domain.c     Wed Feb 22 12:20:06 2006
@@ -346,7 +346,7 @@
     struct vcpu *v, struct vcpu_guest_context *c)
 {
     struct domain *d = v->domain;
-    unsigned long phys_basetab;
+    unsigned long phys_basetab = 0;
     int i, rc;
 
     /*
diff -r 5abf652c4c52 xen/common/elf.c
--- a/xen/common/elf.c  Tue Feb 21 18:36:00 2006
+++ b/xen/common/elf.c  Wed Feb 22 12:20:06 2006
@@ -23,7 +23,8 @@
     Elf_Ehdr *ehdr = (Elf_Ehdr *)dsi->image_addr;
     Elf_Phdr *phdr;
     Elf_Shdr *shdr;
-    unsigned long kernstart = ~0UL, kernend=0UL;
+    unsigned long v_kernstart = ~0UL, v_kernend=0UL;
+    unsigned long p_kernstart = ~0UL, p_kernend=0UL;
     char *shstrtab, *guestinfo=NULL, *p;
     char *elfbase = (char *)dsi->image_addr;
     int h;
@@ -87,21 +88,31 @@
         phdr = (Elf_Phdr *)(elfbase + ehdr->e_phoff + (h*ehdr->e_phentsize));
         if ( !is_loadable_phdr(phdr) )
             continue;
-        if ( phdr->p_paddr < kernstart )
-            kernstart = phdr->p_paddr;
-        if ( (phdr->p_paddr + phdr->p_memsz) > kernend )
-            kernend = phdr->p_paddr + phdr->p_memsz;
-    }
-
-    if ( (kernstart > kernend) || 
-         (ehdr->e_entry < kernstart) || 
-         (ehdr->e_entry > kernend) )
+        printk("%s: phdr: vaddr %08lx paddr %08lx filesz %08lx\n",
+               __FUNCTION__,
+               (unsigned long)phdr->p_vaddr,
+               (unsigned long)phdr->p_paddr,
+               (unsigned long)phdr->p_filesz);
+        if ( phdr->p_vaddr < v_kernstart )
+            v_kernstart = phdr->p_vaddr;
+        if ( (phdr->p_vaddr + phdr->p_memsz) > v_kernend )
+            v_kernend = phdr->p_vaddr + phdr->p_memsz;
+        if ( phdr->p_paddr < p_kernstart )
+            p_kernstart = phdr->p_paddr;
+        if ( (phdr->p_paddr + phdr->p_memsz) > p_kernend )
+            p_kernend = phdr->p_paddr + phdr->p_memsz;
+    }
+
+    if ( (v_kernstart > v_kernend) || 
+         (p_kernstart > p_kernend) || 
+         (ehdr->e_entry < v_kernstart) || 
+         (ehdr->e_entry > v_kernend) )
     {
         printk("Malformed ELF image.\n");
         return -EINVAL;
     }
 
-    dsi->v_start = kernstart;
+    dsi->v_start = v_kernstart;
 
     if ( guestinfo != NULL )
     {
@@ -112,10 +123,26 @@
             dsi->load_symtab = 1;
     }
 
-    dsi->v_kernstart = kernstart;
-    dsi->v_kernend   = kernend;
+    dsi->v_kernstart = v_kernstart;
+    dsi->v_kernend   = v_kernend;
     dsi->v_kernentry = ehdr->e_entry;
     dsi->v_end       = dsi->v_kernend;
+
+    if (p_kernstart == v_kernstart) {
+        /*
+         * Bug compatibility alert: In older linux kernels
+         * p_paddr is broken, it doesn't contain the physical
+         * address but instead is identical to p_vaddr.  Thus
+         * we can't use it directly, instead we'll guess it
+         * using dsi->v_start.
+         */
+        printk("%s: linux kernel paddr quirk\n", __FUNCTION__);
+        dsi->p_kernstart = v_kernstart - dsi->v_start;
+        dsi->p_kernend   = v_kernend   - dsi->v_start;
+    } else {
+        dsi->p_kernstart = p_kernstart;
+        dsi->p_kernend   = p_kernend;
+    }
 
     loadelfsymtab(dsi, 0);
 
@@ -135,10 +162,10 @@
         if ( !is_loadable_phdr(phdr) )
             continue;
         if ( phdr->p_filesz != 0 )
-            memcpy((char *)phdr->p_paddr, elfbase + phdr->p_offset, 
+            memcpy((char *)phdr->p_vaddr, elfbase + phdr->p_offset, 
                    phdr->p_filesz);
         if ( phdr->p_memsz > phdr->p_filesz )
-            memset((char *)phdr->p_paddr + phdr->p_filesz, 0, 
+            memset((char *)phdr->p_vaddr + phdr->p_filesz, 0, 
                    phdr->p_memsz - phdr->p_filesz);
     }
 
diff -r 5abf652c4c52 xen/include/xen/sched.h
--- a/xen/include/xen/sched.h   Tue Feb 21 18:36:00 2006
+++ b/xen/include/xen/sched.h   Wed Feb 22 12:20:06 2006
@@ -165,6 +165,8 @@
     unsigned long v_end;
     unsigned long v_kernstart;
     unsigned long v_kernend;
+    unsigned long p_kernstart;
+    unsigned long p_kernend;
     unsigned long v_kernentry;
     /* Initialised by loader: Private. */
     unsigned int  load_symtab;
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel